懒加载优缺点
优点:懒加载,对象使用的时候才去创建;启动速度快,节省资源
缺点:不利于提前发现错误;初次请求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的循环依赖一样处理,详见前文。