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()为falseif (!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 {@Autowiredprivate LazyConfig lazyConfig;@Overridepublic 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的循环依赖一样处理,详见前文。

Spring源码之@Lazy和预实例化相关推荐

  1. Spring源码剖析-单利Bean的实例化(六)

    前言 前面系列章节我们分析了Spring的IOC的启动流程,包括:容器创建,配置加载,配置解析,Bean注册等几个阶段,所以Bean注册其实就是把Bean的相关属性,依赖关系等封装成BeanDeafi ...

  2. Spring源码解析(五)-Bean的实例化流程(上)

    在前面已经完成了对需要实例化bean的收集并封装成BeanDefinition,并且将BeanPostProcess等组件进行了提前实例化.接下来就到了容器启动的最后一步,也是最复杂的一步-实例化be ...

  3. idea导入spring源码_Spring源码入门到放弃(一):环境准备

    今天开始Spring源码的学习,年后面试Java高级研发岗,Spring底层的知识是必问知识,而且面试官问的很深入,以前没系统的了解过,现在开始恶补. 在此记录学习过程,不定期更新学习笔记.希望对大家 ...

  4. Spring源码之启动过程(四)—— Bean的实例化详解

    前面,我们把Bean的生命周期做了一个概述和梳理,为的是更深刻的理解容器启动及Bean的生命周期,最主要的是Bean的实例化过程,没有看过的,可以进去先看一下(文章链接:Spring源码之Bean的生 ...

  5. Spring源码解析-bean实例化

    Spring源码解析-bean实例化 ​ 本文介绍Spring创建 bean 过程中的第一个步骤:实例化 bean. 1. Bean实例化源码 ​ 虽然实例化Bean有多种方式(包括静态工厂和工厂实例 ...

  6. Spring源码解析 - AbstractBeanFactory 实现接口与父类分析

    2019独角兽企业重金招聘Python工程师标准>>> 我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegi ...

  7. spring 源码_spring源码系列(一)——spring循环引用

    众所周知spring在默认单例的情况下是支持循环引用的 为了节省图片大小我把那些可以动得gif图片做成了只循环一次,如果看到图片不动了请右键选择在新标签打开,那么图片就会动,手机用户则更简单,直接手指 ...

  8. 剑指Spring源码(一)

    Spring,相信每个Java开发都用过,而且是每天都在用,那强大又神秘的IoC,AOP,让我们的开发变得越来越简单,只需要一个注解搞定一切,但是它内部到底是什么样子的呢?跟着我,一起探究Spring ...

  9. Spring源码剖析 循环注入

    版权声明:本文为CSDN博主「shadow?s」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/java_ly ...

最新文章

  1. php 重新载入类文件夹,php-如何配置Behat从应用程序特定文件夹自动加载类
  2. springmvc工作流程简单易懂_三极管的结构和工作特性,简单易懂
  3. RNN失宠、强化学习风头正劲,ICLR 2019的八点参会总结
  4. python界面是什么样子的图片_如何在python界面显示图片
  5. HOWTO:如果检测用户是从系统的“添加/删除”中卸载软件
  6. Linux下的GitHub安装与简单配置教程
  7. 《系统集成项目管理工程师》必背100个知识点-13项目经理是整合者
  8. 转:Android中如何修改系统时间(应用程序获得系统权限)
  9. memset()函数的赋值问题
  10. 鸿蒙系统还会推出吗,华为明年所有自研设备都升级鸿蒙系统,还会推出基于鸿蒙系统的新机...
  11. 自定义 Git - Git 钩子 (自动部署)
  12. 计算机主机箱拆箱,开箱 篇一:拆戴尔3681 SFF 10代小主机
  13. leetcode python3 简单题167. Two Sum II - Input array is sorted
  14. linux中定义用户账户的文件为,Linux中用户和组中认证库和解析库的文件格式以及默认参数定义文件...
  15. 示波器抓取RC663身份证的天线耦合波形
  16. MAC OS升级记录
  17. 如何在线批量进行PDF拆分
  18. 计算机u盘序列号,win10-u盘序列号cmd怎么查
  19. return 不能跳出 forEach 循环
  20. 慧数汽车大数据:中国多功能轿车(旅行车)市场研究报告(2018简版)

热门文章

  1. 个人网站如何集成QQ快捷登录功能?
  2. java写飞控_无人机飞行控制源码(android)
  3. 雷军:十岁的小米乘风破浪,有趣的灵魂一往无前
  4. 使用Acrobat将PDF所有书签批量修改为“适合宽度”显示
  5. Onvif协议控制球机云台
  6. 下载磁力链接的软件推荐
  7. a标签下载txt,jpg文件,不是直接打开的方式
  8. Geany文本编辑器
  9. 闲谈GDP(4)-GDP统计的几种方法
  10. android 先拍照后对焦,何须羡慕诺基亚 安卓也可先拍照后对焦