Spring Bean创建和循环依赖

目录
  • 1 前言
  • 2 Bean 的创建
    • createBeanInstance
    • populateBean
    • initializeBean
    • 循环依赖问题
  • 总结

1 前言

前文已经讲述了Spring BeanFactory 与 FactoryBean 的区别详情,在本文中将继续讲解 Bean 的创建和初始化,在这个环节中将会涉及到 Bean 的创建、初始化和循环依赖内容。

2 Bean 的创建

在前文中已经讲述了 Spring 容器启动的核心方法 refresh,关于 Bean 的创建和初始化方法都是在 finishBeanFactoryInitialization() 中进行处理,在这个阶段就是处理所有剩余的非懒加载的单例对象。

在该方法中,调用 preInstantiateSingletons() 进行 Bean 的所有单实例 bean。 在这个过程中,会获取容器中的所有 Bean, 依次进行初始化和创建对象。获取所有的 Bean 定义信息 beanDefinitionNames。在处理 Bean 时需要判断 Bean 定义信息是不是抽象的,单例,和懒加载。其核心方法为 getBean , 也许大家都知道在获取 Bean 的过程中,会经历 getBean -> doGetBean -> createBean -> doCreateBean 方法调用链,在 Spring 源码中, doXXX 的方法都是实际业务的方法,在 doCreateBean 方法中,createBeanInstance 方法是真实创建 Bean 对象的方法,在 Spring 中,都是采用反射的方法来创建对象的。这些核心的方法都是在 AbstractAutowireCapableBeanFactory 中实现,下图便是 doCreateBean 方法,其中的核心操作有三个: createBeanInstance 、populateBean、initializeBean

createBeanInstance

createBeanInstance 是创建 Bean 对象的方法,这里最终调用的是 instantiateBean 方法,最终的调用栈如下:

AbstractAutowireCapableBeanFactory.instantiate
  -> SimpleInstantiationStrategy.instantiate
      -> BeanUtils.instantiateClass
           -> ctor.newInstance

populateBean

populateBean 是设置 Bean 属性的方法,如下图所示 autowireByName autowireByType 两个方法即是自动注入的方法,以 autowireByName 为例,获取属性是以 getBean 的方式从 IOC 容器中获取对应的 Bean。

initializeBean

初始化 Bean 是在实例化之后的操作,在初始化之前和之后便是 BeanPostProcessor 的操作,初始化的操作便是 invokeInitMethods 的初始化方法。

# 在初始化之前和之后执行
applyBeanPostProcessorsBeforeInitialization
applyBeanPostProcessorsAfterInitialization

初始化 Bean 的操作

初始化之前和之后的操作方法:

循环依赖问题

循环依赖是绕不开的话题,循环依赖的问题具体的表现形式如下:

在讲循环依赖如何结果之前,还是涉及到 Bean 是如何创建的,如下图所示的过程就是解决循环依赖的过程。

  • 1 在创建 A 对象时,需要在 populateBean 填充属性时触发获取 B 对象的操作,这里说一下会在 createBeanInstance 方法中将对象的构造方法放进三级缓存中。
  • 2 在经历了一轮 getBean 和 createBean 之后再次执行到属性赋值操作 populateBean,此时会再次触发获取 A 对象的操作,此时再去获取 A 对象时,会从三级缓存中创建一个半成品 A 对象放进二级缓存中并删除三级缓存,并做返回,此时 B 对象得到属性填充,完成赋值后放进一级缓存中,并将 B 对象返回到 1 步骤。
  • 3 第一步的创建 A 对象继续,完成属性赋值后,会将对象放进一级缓存中,并删除二级缓存。 创建 Bean 的过程如下图所示,Abstra ctAutowireCapableBeanFactory.doCreateBean 方法核心内容如下:

获取单例 Bean 的方法:

初始化的方法如下所示:

通过以上的三个步骤,就实现了循环依赖的问题解决,也完成了 Bean 对象的创建过程。

为什么要使用三级缓存呢,说到底是要解决以下问题:

  • 1 如果采用了一级缓存,如果没有存在循环依赖的问题,确实是可以的。如果有存在前图中的循环依赖问题,那么就无法解决了,就只能采用两级缓存才能解决了。
  • 2 如果使用了两级缓存,确实能解决一部分的问题。但是 Bean 被 AOP 代理,再使用两级缓存就不能解决问题了,必须采用三级缓存。

总结

文中主要讲述了 Spring 容器中 Bean 的创建过程已经主要的方法,另外也着重分析了循环依赖的问题.

到此这篇关于Spring-Bean创建和循环依赖的文章就介绍到这了,更多相关Spring Bean 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Bean创建和循环依赖

    目录 1 前言 2 Bean 的创建 createBeanInstance populateBean initializeBean 循环依赖问题 总结 1 前言 前文已经讲述了Spring BeanFactory 与 FactoryBean 的区别详情,在本文中将继续讲解 Bean 的创建和初始化,在这个环节中将会涉及到 Bean 的创建.初始化和循环依赖内容. 2 Bean 的创建 在前文中已经讲述了 Spring 容器启动的核心方法 refresh,关于 Bean 的创建和初始化方法都是在 

  • 关于Java Spring三级缓存和循环依赖的深入理解

    目录 一.什么是循环依赖?什么是三级缓存? 二.三级缓存如何解决循环依赖? 三.使用二级缓存能不能解决循环依赖? 一.什么是循环依赖?什么是三级缓存? [什么是循环依赖]什么是循环依赖很好理解,当我们代码中出现,形如BeanA类中依赖注入BeanB类,BeanB类依赖注入A类时,在IOC过程中creaBean实例化A之后,发现并不能直接initbeanA对象,需要注入B对象,发现对象池里还没有B对象.通过构建函数创建B对象的实例化.又因B对象需要注入A对象,发现对象池里还没有A对象,就会套娃.

  • Spring三级缓存解决循环依赖

    目录 一级缓存 为什么不能在实例化A之后就放入Map? 二级缓存 二级缓存已然解决了循环依赖问题,为什么还需要三级缓存? 三级缓存 源码 我们都知道Spring中的BeanFactory是一个IOC容器,负责创建Bean和缓存一些单例的Bean对象,以供项目运行过程中使用. 创建Bean的大概的过程: 实例化Bean对象,为Bean对象在内存中分配空间,各属性赋值为默认值 初始化Bean对象,为Bean对象填充属性 将Bean放入缓存 首先,容器为了缓存这些单例的Bean需要一个数据结构来存储,

  • spring Bean创建的完整过程记录

    目录 前言 bean创建的流程图 快速开始 总结 前言 复习一下spring实现IOC的源码流程准备工作: ​强烈建议大家从git上拉取spring源码来学习Spring源码.因为里面相较于IDEA生成的会有注释,里面有的方法会有注释看起来会省力一点. ​以下都是用5.0.2版本来做阐述. bean创建的流程图 写在前面:建议大家一定要自己用实例跑一遍,做好记录.如果只是看看会非常抽象.此流程图作为梗概,便于加强记忆和理解,新手或无基础的有个印象即可.等跟随本文走通一遍,在回过头看这个图,或许会

  • 一篇文章带你理解Java Spring三级缓存和循环依赖

    目录 一.什么是循环依赖?什么是三级缓存 二.三级缓存如何解决循环依赖? 三.使用二级缓存能不能解决循环依赖? 总结 一.什么是循环依赖?什么是三级缓存 [什么是循环依赖]什么是循环依赖很好理解,当我们代码中出现,形如BeanA类中依赖注入BeanB类,BeanB类依赖注入A类时,在IOC过程中creaBean实例化A之后,发现并不能直接initbeanA对象,需要注入B对象,发现对象池里还没有B对象.通过构建函数创建B对象的实例化.又因B对象需要注入A对象,发现对象池里还没有A对象,就会套娃.

  • Spring源码之循环依赖之三级缓存详解

    目录 循环依赖 定义 三种循环依赖的情况 1.构造器循环依赖 2.settler循环依赖 3.prototype范围的依赖处理 三级缓存机制 整体分析 源码分析 面试题 总结 循环依赖 定义 循环依赖就 循环引用,就是两个或多个 bean 相互之间的持有对方,比如 CircleA 引用 CircleB , CircleB 引用 CircleC, CircleC 引用 CircleA ,则它们最终反映为 个环.此处不是循环调用,循环调用是方法之间的环调用. 循环调用是无法解决的,除非有终结条件,否

  • spring boot创建项目包依赖问题的解决

    今天捣腾了spring boot,按照官网案例,缺发现本地无论包依赖出现问题,并且无法启动,一整天在踩maven的坑,记录下这个血的教训. 1.spring-core依赖包问题 运行application,发现缺少依赖的spring-core包: 但是spring boot的包都是通过parent的starter引入的,通过mvn denpendency:tree查看项目的jar依赖信息:  发现spring-core依赖包是存在的,但是为什么运行的时候回报错找不到类. 倒腾了一个下午试过各种方

  • Spring循环依赖正确性及Bean注入的顺序关系详解

    一.前言 我们知道 Spring 可以是懒加载的,就是当真正使用到 Bean 的时候才实例化 Bean.当然也不全是这样,例如配置 Bean 的 lazy-init 属性,可以控制 Spring 的加载时机.现在机器的性能.内存等都比较高,基本上也不使用懒加载,在容器启动时候来加载bean,启动时间稍微长一点儿,这样在实际获取 bean 供业务使用时,就可以减轻不少负担,这个后面再做分析. 我们使用到 Bean 的时候,最直接的方式就是从 Factroy 中获取,这个就是加载 Bean 实例的源

  • Spring IOC原理补充说明(循环依赖、Bean作用域等)

    前言 通过之前的几篇文章将Spring基于XML配置的IOC原理分析完成,但其中还有一些比较重要的细节没有分析总结,比如循环依赖的解决.作用域的实现原理.BeanPostProcessor的执行时机以及SpringBoot零配置实现原理(@ComponentScan.@Import.@ImportSource.@Bean注解的使用和解析)等等.下面就先来看看循环依赖是怎么解决的,在此之前一定要熟悉整个Bean的实例化过程,本篇只会贴出关键性代码. 正文 循环依赖 首先来看几个问题: 什么是循环依

  • Java Spring循环依赖原理与bean的生命周期图文案例详解

    前言 Spring是如何处理循环依赖的,又是怎么做到,互相注入对方的proxy bean而不是raw bean的?现在就分析一下 一.循环依赖是什么 Spring中放入两个Service,分别是C1和C2,然后C1和C2又互为对方的成员变量.这种情况C1和C2就可以说是相互循环依赖了 二.源码图解 1. bean的主要生命周期图解 上图是一个没有循坏依赖的bean的主要生命周期节点,下图的循坏依赖可以结合该图解一起看 2.循环依赖图解 可以看到里面有一个很重要的逻辑: 当一个bean经过所有的步

随机推荐