Spring(SpringBoot) 您所在的位置:网站首页 延迟加载dll原理 Spring(SpringBoot)

Spring(SpringBoot)

2024-04-13 07:36| 来源: 网络整理| 查看: 265

简介

本文介绍Spring中Bean的生命周期--延迟初始化。

延迟初始化通常又被称为“懒加载”。延迟初始化定义:在启动时不初始化Bean,直到用到这个Bean的时候才去初始化。默认情况下,Bean在启动时进行初始化。延迟加载用法

​法1:在@Component类上加上@Lazy注解​

@Lazy@Componentpublic class XXXX { ...}

​法2:@Configuration类中配置@Bean时添加@Lazy注解​

@Configurationpublic class XXXX { @Lazy @Bean public XXX getXXX() { return new XXX(); }}

​ 法3:@ComponentScan配置​

@ComponentScan(value = "XXX.XXX", lazyInit = true)@Configurationpublic class XXXX { ...}

​法4:在XML文件中直接配置标签属性​

​全局与局部延迟初始化​

上边这些配置方法都是局部延迟初始化,全局配置延迟初始化的方法如下:

​法1:application.yml​

spring.main.lazy-initialization=true

​法2:在XML文件中直接配置标签属性​

​法3:主程序开启​

@SpringBootApplicationpublic class DemoSpringbootApplication { @Lazy public static void main(String[] args) { SpringApplication sa = new SpringApplication(DemoSpringbootApplication.class);

sa.setLazyInitialization(true); sa.run(args); }}

​法4:主程序开启​

@SpringBootApplicationpublic class DemoSpringbootApplication { @Lazy public static void main(String[] args) { SpringApplicationBuilder sab = new SpringApplicationBuilder(DemoSpringbootApplication.class);

sab.lazyInitialization(true).run(args); }}

简单示例

​Bean​

package com.example.lazy;

import org.springframework.context.annotation.Lazy;import org.springframework.stereotype.Component;

@Component@Lazypublic class LazyTest { public LazyTest() { System.out.println("[LazyTest.LazyTest]: 10"); }

public void print() { System.out.println("This is LazyTest print"); }}

​ApplicationContext工具类​

package com.example.lazy;

import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;

@Componentpublic class SpringApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context;

public void setApplicationContext(ApplicationContext context) throws BeansException { SpringApplicationContextHolder.context = context; }

public static ApplicationContext getContext() { return context; }}

​测试类​

package com.example.controller;

import com.example.lazy.LazyTest;import com.example.lazy.SpringApplicationContextHolder;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;

@RestControllerpublic class HelloController {

@GetMapping("/test1") public String test1() { LazyTest lazyTest = SpringApplicationContextHolder.getContext().getBean(LazyTest.class); System.out.println("即将执行lazy类的方法"); lazyTest.print();

return "test1 success"; }}

​测试​

启动程序。结果:无相关打印。

访问:​​localhost:8080/test1​​

结果:

[LazyTest.LazyTest]: 10即将执行lazy类的方法This is LazyTest print

 如果将LazyTest类上的@Lazy去掉,则一启动,就会打印构造函数中的内容:

[LazyTest.LazyTest]: 10使用场景

1.解决循环依赖

2.解决在@Configuration中注入@Service注解的类

失效示例

​非延迟加载的Controller​

@Controllerpublic class TestController implements InitializingBean{ @Autowired private TestService testService; @Override public void afterPropertiesSet() throws Exception { System.out.println("testController Initializing"); }}

​延迟加载的Service​

@Lazy@Servicepublic class TestService implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("testService Initializing"); }}

​测试​

启动打印:

testService InitializingtestController Initializing

​分析​

        启动完Spring程序后输出了TestService里面打印的字符串。明明使用了@Lazy注解,却没有其作用,在Spring启动项目时还是加载了这个类。这就涉及到@Autowired等自动注入注解的使用了。

        由于Controller类不是延迟加载的,且里面使用@Autowired自动注入注解注入了Service,因此在程序初始化时Controller将会被初始化,同时在处理@Autowired注解的字段时,会调用getBean方法从Spring工厂中获取字段的bean对象,因此通过@Autowired路线加在了Service,这就导致了@Lazy注解失效了,因此虽然没通过refresh方法流程初始化,但是却通过@Autowired的处理类初始化了。

​解决方法:​

法1:把Controller也改成@Lazy,让其在启动时不被加载,不触发@Autowired注解依赖链的调用即可。如下:

@Lazy@Controllerpublic class TestController implements InitializingBean{ @Autowired private TestService testService; @Override public void afterPropertiesSet() throws Exception { System.out.println("testController Initializing"); }}

法2:@Autowired的地方加上@Lazy。如下:

@Controllerpublic class TestController implements InitializingBean{ @Autowired @Lazy private TestService testService; @Override public void afterPropertiesSet() throws Exception { System.out.println("testController Initializing"); }}原理

​简介​

        容器启动的时候 ​只处理 non-lazy-init bean,懒加载的bean在Spring启动阶段根本不做任何处理。​

​Spring 初始化入口 refresh​

public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh();

// Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory);

try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Instantiate all remaining (non-lazy-init) singletons. // 初始化所有非懒加载的bean finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event. finishRefresh(); }catch(){} }}

finishBeanFactoryInitialization(beanFactory);是跟本次主题有关的。

​finishBeanFactoryInitialization(beanFactory)​

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { //其他代码

// 本处关注的代码 beanFactory.preInstantiateSingletons(); } // 其他代码}

finishBeanFactoryInitialization(beanFactory)里头有个初始化​non-lazy-init bean​的函数 preInstantiateSingletons()

​preInstantiateSingletons​

具体逻辑如下

1.对beanNames 集合遍历获取每个BeanDefinition

2.判断是否是懒加载的,如果不是则继续处理(​non-lazy-init bean 不做处理​)

3.判断是否是factorybean 如果不是则进行实例化并依赖注入

public void preInstantiateSingletons() throws BeansException { // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. // 所有beanDefinition集合 List beanNames = new ArrayList(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans... // 触发所有非懒加载单例bean的初始化 for (String beanName : beanNames) { // 获取bean 定义 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 判断是否是懒加载单例bean。如果是单例的并且不是懒加载的则在Spring 容器 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 判断是否是FactoryBean if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean factory = (FactoryBean) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction) ((SmartFactoryBean) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { // 如果是普通bean则进行初始化依赖注入,此 getBean(beanName)接下来触发的逻辑跟 // context.getBean("beanName") 所触发的逻辑是一样的 getBean(beanName); } } }}



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有