• Spring源码之@Lazy和预实例化


    https://www.cnblogs.com/yanze/p/10243348.html

    懒加载优缺点

    优点:懒加载,对象使用的时候才去创建;启动速度快,节省资源
    缺点:不利于提前发现错误;初次请求getBean时慢

    三种情况

    1. 只有一个@Lazy注解的类
    2. 一个Singleton类,依赖@Lazy的类
    3. 两个@Lazy的类互相依赖

    只有一个@Lazy注解的类分析

    @Lazy注解的类在容器初始化时,不执行getBean

    singleton 的bean初始化是通过调用AbstractApplicationContext的finishBeanFactoryInitialization方法完成。

    当用@Lazy注解时,执行到DefaultListableBeanFactory的preInstantiateSingletons方法时,不满足条件,故在容器初始化时,不会进行预实例化。不会调用后面getBean方法。

    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        ......
    }
    

    调用链:

    SpringApplication#run() --> SpringApplication#refreshContext() --> SpringApplication#refresh() --> ServletWebServerApplicationContext#refresh() --> AbstractApplicationContext#refresh() --> AbstractApplicationContext#finishBeanFactoryInitialization() --> DefaultListableBeanFactory#preInstantiateSingletons()

    preInstantiateSingletons源码:

    @Override
    public void preInstantiateSingletons() throws BeansException {
    	if (logger.isTraceEnabled()) {
    		logger.trace("Pre-instantiating singletons in " + this);
    	}
    
    	// 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.
    	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
    	// Trigger initialization of all non-lazy singleton beans...
    	for (String beanName : beanNames) {
    		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    		//!bd.isLazyInit()为false
    		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    			if (isFactoryBean(beanName)) {
    				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    				if (bean instanceof FactoryBean) {
    					FactoryBean<?> factory = (FactoryBean<?>) bean;
    					boolean isEagerInit;
    					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
    						isEagerInit = AccessController.doPrivileged(
    								(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
    								getAccessControlContext());
    					}
    					else {
    						isEagerInit = (factory instanceof SmartFactoryBean &&
    								((SmartFactoryBean<?>) factory).isEagerInit());
    					}
    					if (isEagerInit) {
    						getBean(beanName);
    					}
    				}
    			}
    			else {
    				getBean(beanName);
    			}
    		}
    	}
    
    	// Trigger post-initialization callback for all applicable beans...
    	for (String beanName : beanNames) {
    		Object singletonInstance = getSingleton(beanName);
    		if (singletonInstance instanceof SmartInitializingSingleton) {
    			StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
    					.tag("beanName", beanName);
    			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    			if (System.getSecurityManager() != null) {
    				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    					smartSingleton.afterSingletonsInstantiated();
    					return null;
    				}, getAccessControlContext());
    			}
    			else {
    				smartSingleton.afterSingletonsInstantiated();
    			}
    			smartInitialize.end();
    		}
    	}
    }
    
    
    第一次对@Lazy修饰的类调用getBean方法

    一种写法:

    public String getLazyBean() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LazyConfig.class);
        Object lazyConfig = context.getBean("lazyConfig");
        return lazyConfig.toString();
    }
    
    @Component
    @Lazy
    public class LazyConfig {
        ......
    }
    

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LazyConfig.class);会调用AnnotationConfigApplicationContext初始化方法,进行refresh()

    public AnnotationConfigApplicationContext(String... basePackages) {
    	this();
    	scan(basePackages);
    	refresh();
    }
    

    而@Lazy注解的类真正初始化则在context.getBean("lazyConfig");过程,调用到AbstractApplicationContext类getBean方法

    @Override
    public Object getBean(String name) throws BeansException {
    	assertBeanFactoryActive();
    	return getBeanFactory().getBean(name);
    }
    

    然后调用到AbstractBeanFactory#doGetBean,后面和预实例化中过程一样,最后调用到AbstractAutowireCapableBeanFactory#doCreateBean();

    	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    
    		// Instantiate the bean.
    		BeanWrapper instanceWrapper = null;
    		if (instanceWrapper == null) {
    			// 实例化对象
    			instanceWrapper = createBeanInstance(beanName, mbd, args);
    		}
    		Object bean = instanceWrapper.getWrappedInstance();
    
            ......
            
    		// Eagerly cache singletons to be able to resolve circular references
    		// even when triggered by lifecycle interfaces like BeanFactoryAware.
    		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    				isSingletonCurrentlyInCreation(beanName));
    		if (earlySingletonExposure) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Eagerly caching bean '" + beanName +
    						"' to allow for resolving potential circular references");
    			}
    			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    		}
    
    		// Initialize the bean instance.
    		Object exposedObject = bean;
    		try {
    		    //属性注入
    			populateBean(beanName, mbd, instanceWrapper);
    			//初始化对象
    			exposedObject = initializeBean(beanName, exposedObject, mbd);
    		}
    
            ......
            
    		return exposedObject;
    	}
    

    调用链:

    AbstractApplicationContext#getBean() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean() --> AbstractAutowireCapableBeanFactory#createBean()
    --> AbstractAutowireCapableBeanFactory#doCreateBean() --> AbstractAutowireCapableBeanFactory#createBeanInstance()、populateBean()、initializeBean()

    一个Singleton类,依赖@Lazy的类

    一个例子
    @Service
    public class LazyServiceImpl implements LazyService {
    
        @Autowired
        private LazyConfig lazyConfig;
    
        @Override
        public void lazyDependent() {
            ......
        }
    }
    
    @Component
    @Lazy
    public class LazyConfig {
        ......
    }
    
    分析

    在容器初始化时,preInstantiateSingletons会对上面的LazyServiceImpl进行getBean的处理,执行到AbstractAutowireCapableBeanFactory类populateBean方法进行属性注入时,通过如下调用链对上面的LazyConfig类进行getBean处理

    AbstractAutowireCapableBeanFactory#populateBean() --> AutowiredAnnotationBeanPostProcessor#postProcessProperties() --> InjectionMetadata#inject() --> AutowiredAnnotationBeanPostProcessor#inject() --> DefaultListableBeanFactory#resolveDependency() --> DefaultListableBeanFactory#doResolveDependency() --> DependencyDescriptor#resolveCandidate() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean()

    从而一个Singleton类,依赖@Lazy的类,这个被依赖的@Lazy注释的类,也会被初始化

    两个@Lazy的类互相依赖

    容器初始化时都不调用getBean进行初始化,在其中一个getBean时,后面和singleton的循环依赖一样处理,详见前文。

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出。
  • 相关阅读:
    H5前端上传文件的几个解决方案
    MyEclipse和Eclipse各个版本的汉化破解(包括7.59.0和Eclips的ehelios、indigo各版本)
    学习C#中的事件和委托
    JS学习笔记(一)JS处理JSON数据
    图解Eclipse开发C++、C语言的配置过程使用CDT和MinGw
    ASP.NET使用C#实现的最简单的验证码方法
    微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结
    PHP开发笔记(二)PHP的json_encode和json_decode问题
    C博客作业00——我的第一篇博客
    extern "c"
  • 原文地址:https://www.cnblogs.com/caozibiao/p/13969795.html
Copyright © 2020-2023  润新知