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方法。

  1. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
  2. ......
  3. }

调用链:

SpringApplication#run() --> SpringApplication#refreshContext() --> SpringApplication#refresh() --> ServletWebServerApplicationContext#refresh() --> AbstractApplicationContext#refresh() --> AbstractApplicationContext#finishBeanFactoryInitialization() --> DefaultListableBeanFactory#preInstantiateSingletons()

preInstantiateSingletons源码:

  1. @Override
  2. public void preInstantiateSingletons() throws BeansException {
  3. if (logger.isTraceEnabled()) {
  4. logger.trace("Pre-instantiating singletons in " + this);
  5. }
  6. // Iterate over a copy to allow for init methods which in turn register new bean definitions.
  7. // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
  8. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
  9. // Trigger initialization of all non-lazy singleton beans...
  10. for (String beanName : beanNames) {
  11. RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
  12. //!bd.isLazyInit()为false
  13. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
  14. if (isFactoryBean(beanName)) {
  15. Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
  16. if (bean instanceof FactoryBean) {
  17. FactoryBean<?> factory = (FactoryBean<?>) bean;
  18. boolean isEagerInit;
  19. if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
  20. isEagerInit = AccessController.doPrivileged(
  21. (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
  22. getAccessControlContext());
  23. }
  24. else {
  25. isEagerInit = (factory instanceof SmartFactoryBean &&
  26. ((SmartFactoryBean<?>) factory).isEagerInit());
  27. }
  28. if (isEagerInit) {
  29. getBean(beanName);
  30. }
  31. }
  32. }
  33. else {
  34. getBean(beanName);
  35. }
  36. }
  37. }
  38. // Trigger post-initialization callback for all applicable beans...
  39. for (String beanName : beanNames) {
  40. Object singletonInstance = getSingleton(beanName);
  41. if (singletonInstance instanceof SmartInitializingSingleton) {
  42. StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
  43. .tag("beanName", beanName);
  44. SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
  45. if (System.getSecurityManager() != null) {
  46. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  47. smartSingleton.afterSingletonsInstantiated();
  48. return null;
  49. }, getAccessControlContext());
  50. }
  51. else {
  52. smartSingleton.afterSingletonsInstantiated();
  53. }
  54. smartInitialize.end();
  55. }
  56. }
  57. }
第一次对@Lazy修饰的类调用getBean方法

一种写法:

  1. public String getLazyBean() {
  2. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LazyConfig.class);
  3. Object lazyConfig = context.getBean("lazyConfig");
  4. return lazyConfig.toString();
  5. }
  1. @Component
  2. @Lazy
  3. public class LazyConfig {
  4. ......
  5. }

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LazyConfig.class);会调用AnnotationConfigApplicationContext初始化方法,进行refresh()

  1. public AnnotationConfigApplicationContext(String... basePackages) {
  2. this();
  3. scan(basePackages);
  4. refresh();
  5. }

而@Lazy注解的类真正初始化则在context.getBean("lazyConfig");过程,调用到AbstractApplicationContext类getBean方法

  1. @Override
  2. public Object getBean(String name) throws BeansException {
  3. assertBeanFactoryActive();
  4. return getBeanFactory().getBean(name);
  5. }

然后调用到AbstractBeanFactory#doGetBean,后面和预实例化中过程一样,最后调用到AbstractAutowireCapableBeanFactory#doCreateBean();

  1. protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  2. throws BeanCreationException {
  3. // Instantiate the bean.
  4. BeanWrapper instanceWrapper = null;
  5. if (instanceWrapper == null) {
  6. // 实例化对象
  7. instanceWrapper = createBeanInstance(beanName, mbd, args);
  8. }
  9. Object bean = instanceWrapper.getWrappedInstance();
  10. ......
  11. // Eagerly cache singletons to be able to resolve circular references
  12. // even when triggered by lifecycle interfaces like BeanFactoryAware.
  13. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  14. isSingletonCurrentlyInCreation(beanName));
  15. if (earlySingletonExposure) {
  16. if (logger.isTraceEnabled()) {
  17. logger.trace("Eagerly caching bean '" + beanName +
  18. "' to allow for resolving potential circular references");
  19. }
  20. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  21. }
  22. // Initialize the bean instance.
  23. Object exposedObject = bean;
  24. try {
  25. //属性注入
  26. populateBean(beanName, mbd, instanceWrapper);
  27. //初始化对象
  28. exposedObject = initializeBean(beanName, exposedObject, mbd);
  29. }
  30. ......
  31. return exposedObject;
  32. }

调用链:

AbstractApplicationContext#getBean() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean() --> AbstractAutowireCapableBeanFactory#createBean()

--> AbstractAutowireCapableBeanFactory#doCreateBean() --> AbstractAutowireCapableBeanFactory#createBeanInstance()、populateBean()、initializeBean()

一个Singleton类,依赖@Lazy的类

一个例子
  1. @Service
  2. public class LazyServiceImpl implements LazyService {
  3. @Autowired
  4. private LazyConfig lazyConfig;
  5. @Override
  6. public void lazyDependent() {
  7. ......
  8. }
  9. }
  1. @Component
  2. @Lazy
  3. public class LazyConfig {
  4. ......
  5. }
分析

在容器初始化时,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实例化过程、byName与byType及FactoryBean获取Bean源码实现

    原型Bean加载过程 之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean,看一下定义方式: & ...

  2. Spring 源码学习 - 单例bean的实例化过程

    本文作者:geek,一个聪明好学的同事 1. 简介 开发中我们常用@Commpont,@Service,@Resource等注解或者配置xml去声明一个类,使其成为spring容器中的bean,以下我 ...

  3. Bean实例化(Spring源码阅读)-我们到底能走多远系列(33)

    我们到底能走多远系列(33) 扯淡: 各位:    命运就算颠沛流离   命运就算曲折离奇   命运就算恐吓着你做人没趣味   别流泪 心酸 更不应舍弃   ... 主题: Spring源码阅读还在继 ...

  4. Spring 源码分析之 bean 实例化原理

    本次主要想写spring bean的实例化相关的内容.创建spring bean 实例是spring bean 生命周期的第一阶段.bean 的生命周期主要有如下几个步骤: 创建bean的实例 给实例 ...

  5. 【转载】Spring 源码分析之 bean 实例化原理

    本次主要想写spring bean的实例化相关的内容.创建spring bean 实例是spring bean 生命周期的第一阶段.bean 的生命周期主要有如下几个步骤: 创建bean的实例 给实例 ...

  6. Spring源码-IOC部分-Bean实例化过程【5】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

  7. Spring 源码学习——Aop

    Spring 源码学习--Aop 什么是 AOP 以下是百度百科的解释:AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程通过预编译的方式和运行期动态代理实 ...

  8. Spring源码分析之`BeanFactoryPostProcessor`调用过程

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 本文内容: AbstractApplicationContext#refresh前部分的一点小内容 ...

  9. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

随机推荐

  1. MeteoInfoLab脚本示例:AMSR-E卫星数据投影

    AMSR-E(http://nsidc.org/data/amsre/index.html)数据中的Land3数据是HDF-EOS4格式,投影是Cylindrical_Equal_Area.这里示例读 ...

  2. 工业级wifi模块

    工业级wifi模块 工业级wifi模块ZLSN7004是上海卓岚开发的一款高性能的Wifi.以太网转串口模块.与普通的wifi模块定位在低成本不同,7004定位在高稳定性.丰富功能,设计目标是面向对功 ...

  3. 程序员的“三十而已”,你都30岁了,不会还在XXX吧?

    一部<三十而已>火了 太太们的包包鄙视链出圈了 有人的地方就有江湖 是的,程序员入圈是容易的 不需要4万的LV,更不需要限量版的爱马仕 只需要一件耐躁的格子衫 然而,程序员的30岁, 却说 ...

  4. 【循环矩阵乘优化DP】BZOJ 2510 弱题

    题目大意 有 \(M\) 个球,一开始每个球均有一个初始标号,标号范围为 \(1\) - \(N\) 且为整数,标号为 \(i\) 的球有 \(a_i\) 个,并保证 \(\sum a_i = M\) ...

  5. net core 微服务 快速开发框架

    dymDemo github 地址:https://github.com/duyanming/dymDemo dym 分布式开发框架 Demo 熔断 限流 事件总线(包括基于内存的.rabbitmq的 ...

  6. C# 将Excel里面的数据填充到DataSet中

    /// <summary> /// 将Excel表里的数据填充到DataSet中 /// </summary> /// <param name="filenam ...

  7. 远程Jenkins新增Mac电脑节点

    一,前言 上一篇博客Jenkins集成appium自动化测试(Windows篇)介绍了怎么使用远程Jenkins新建节点连接本地Windows电脑进行Appium自动化测试集成. 但是在做ios Ap ...

  8. 基于risc-v架构cpu

    一.定义:    CPU ,全称为中央处理器单元,简称为处理器,是一个不算年轻的概念 早在 20 世纪60 年代便己诞生了第一款 CPU请注意区分"处理器"和"处理器核& ...

  9. BeanCopier的使用

    BeanCopier进行的是bean之间的copy,从一个类到另一个类,进行属性值的拷贝. 成功copy的条件: 1.属性的类型和名称都相同 2.目标类的setter缺少或缺失会导致拷贝失败,名称相同 ...

  10. 初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯

    初探RT-Thread系统在GD32E103x芯片上的使用,点亮LED灯 前言 ​ 随着中美贸易战的加剧,很多公司越来越重视使用国产技术的重要性.使用国产技术,一方面可规避国外对技术的封锁造成产品核心 ...