zoukankan      html  css  js  c++  java
  • 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的循环依赖一样处理,详见前文。

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出。
  • 相关阅读:
    【mysql+RBAC】RBAC权限处理(转载:http://www.cnblogs.com/xiaoxi/p/5889486.html 平凡希)
    【小程序】获取微信 自带的 收货地址获取和整理
    【TP3.2】跨库操作和跨域操作
    【JS】一款好用的JS日历选择插件【bootstrap-datetimepicker.js】
    Python 读写文件中w与wt, r与rt的区别
    Python 在序列上跟踪索引和值
    SoapUI 使用变量
    python 跳过可迭代对象的开始部分
    Python 迭代器切片
    Python: 类中为什么要定义__init__()方法
  • 原文地址:https://www.cnblogs.com/caozibiao/p/13969795.html
Copyright © 2011-2022 走看看