Spring原始碼之@Lazy和預例項化
懶載入優缺點
優點:懶載入,物件使用的時候才去建立;啟動速度快,節省資源
缺點:不利於提前發現錯誤;初次請求getBean時慢
三種情況
- 只有一個@Lazy註解的類
- 一個Singleton類,依賴@Lazy的類
- 兩個@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的迴圈依賴一樣處理,詳見前文。