1. 程式人生 > 實用技巧 >Spring原始碼之@Lazy和預例項化

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的迴圈依賴一樣處理,詳見前文。