闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

前言

初夏时节, 时间: AM 7.30分左右, 空无一人的健身房里,一个硕大的身体在跑步机上扭动着, 不一会头上便挥汗如雨, 他嘴上还不时嘀咕着

"循环依赖,单例模式,Bean的定位加载注册,原型模式...", 渐渐跑着跑着就变成了慢慢悠悠的走走歇歇,忽然间感觉肩膀好像被砖头砸了一下,

身后传来一句 "你张大胖减肥是不可能减肥的,就是在健身房里划划水才能维持的了生活 !" ,

大胖被拍的浑身一惊, 看了眼一身运动装的 Mason, 急忙反驳道 "没有调查就没有发言权, 俺只是暂时休息下, 今天都已经跑了好几个小时了呢,倒是 Mason 你像是来假健身的...",

Mason 笑笑说 "哎呀呀, 你这么厉害呢,可惟独肚子上的赘肉骗不了人啊,最近面试的怎么样?"

大胖 一脸愁容的说道: "最近招聘市场很给力,我也参加了不少面试,就是每次聊到 Spring 时被面试官三连追问 Spring是如何解决循环依赖, 而我对着个问题查了很多资料,但也就能回答个一知半解,然后就叫我回去等通知了..."

Mason 在跑步机上边跑边说 "Spring 解决循环依赖的这个场景, 其实也可以映射到生活中, 比如 你工作日睡过了又害怕迟到扣钱,就在 DD出行 App上选择一个起始地打车, 同一时间来了两辆 DD专车, 你也没有check车牌就上车了, 司机也没check你拉上就走,你一上车就聚精会神看起宅舞视频, 结果到达别人的目的地发现上错车,既迟到了又要付来回路费,那么问题来了 你为什么会上错车呢? "

大胖 挠挠头回答道: "因为睡过了怕迟到啊! 呸,不对, 因为要早起去打工!"

Mason 白了张大胖一眼说: "起不来是因为你天天熬夜,坐错车是因为两个原因: 1.没有check车牌 2.DD专车不止一辆"

大胖 一脸懵X 的问道 "绕了半天, 那这上错车和Spring创建Bean时的循环依赖又有什么关系呢 ?"

Mason 一脸这孩子没救了的表情回答道 "循环依赖的触发条件就是, 你上了别人的DD专车, 而你打DD专车, 判断是否循环依赖就需要 check车牌,如果要彻底根治循环依赖就必须让世界上的 DD专车 只有一辆. Spring 中的循环依赖也是同理!"

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

见微知著

我们暂不讨论 Spring 的循环依赖, 先看一道 LeetCode 题目 141. 环形链表 扩展: 在多线程环境下使用JDK1.7中的HashMap, 并发调用resize()时会出现环形链表,后再get()会导致CPU 100%, 那我们该如何去判断环形链表呢?

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

<code>输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。/<code>
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

示例 2:

<code>输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。/<code>
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

示例 3:

<code>输入:head = [1], pos = -1
输出:false
解释:链表中没有环。/<code>
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

那么 Spring 中是用那种方式发现 循环依赖的呢 ? (文章结尾揭晓答案)

<code>//  Definition for singly-linked list.
public class ListNode {
    public int val;
    public ListNode next;
    public ListNode(int x) {
        val = x;
    }
}/<code>

Set判重

<code>  public boolean hasCycle_Set(ListNode head) {

        // 如果入参链表过短则不存在环
        if (head == null || head.next == null) {
            return false;
        }

        HashSet set = new HashSet<>();

        // 如果 遍历到最后任然没有发现环则不存在环
        while (head.next != null){

            // 将每一个遍历过的元素存入,之后判重
            if (set.contains(head)){
                return true;
            }

            set.add(head);
            head = head.next;
        }

        return false;
    }/<code>
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

快慢指针判重

<code> public boolean hasCycle_QuickSlowPointer (ListNode head) {

        // 如果入参链表过短则不存在环
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head;

        // 如果 快指针遍历到最后仍然没有发现环则不存在环
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;

            // 快指针每轮走两步 慢指针每轮走一步 如果有环快慢指针最终就会相遇
            if (slow == fast){
                return true;
            }
        }
        return false;
    }/<code>
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

新整了个活, 今后长期维护的一个LeetCode题解库,欢迎 Star

LeetCode 渐进式题解库: 让天下没有难刷的题 (Java)

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

Spring 中常用的两种 Bean DI 方式的循环依赖示例

Spring DI (Dependency Injection 依赖注入) 是指 Bean 被动接受其他 Bean的依赖注入而不自己主动去找, 简而言之 Bean 不会从容器中查找它依赖的 Bean , 而是靠容器实例化 Bean 时由容器将它依赖的 Bean 注入, 此举与Java 类实例化流程相反.

构造器 DI 示例代码(基于Spring 5.1.6)

<code>package org.springframework.context.annotationX.circular.constructor;

import org.springframework.stereotype.Component;

/**
 * Spring Constructor DI 循环依赖  Bean1 Demo
 */
@Component
public class Bean1ConstructorBean2Demo {

   private Bean2ConstructorBean1Demo bean2;

    public Bean1ConstructorBean2Demo(Bean2ConstructorBean1Demo bean2DependBean1Demo) {
        this.bean2 = bean2DependBean1Demo;
    }

    public void hello() {
        bean2.hello();
    }
}
/<code>
<code>package org.springframework.context.annotationX.circular.constructor;

import org.springframework.stereotype.Component;

/**
 * Spring Constructor DI  循环依赖  Bean2 Demo
 */
@Component
public class Bean2ConstructorBean1Demo {

    private Bean1ConstructorBean2Demo bean1;

    public Bean2ConstructorBean1Demo(Bean1ConstructorBean2Demo bean1DependBean2Demo1) {
        bean1 = bean1DependBean2Demo1;
    }

    public void hello() {
        System.out.println("Run Circular Dependency Success");
    }
}
/<code>

注解自动装配 DI 示例代码

<code>package org.springframework.context.annotationX.circular.autowired;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Spring  @Autowired DI 循环依赖  Bean1 Demo
 */
@Component
public class Bean1AutowiredBean2Demo {

   @Autowired
   private Bean2AutowiredBean1Demo bean2;

    public void hello() {
        bean2.hello();
    }
}/<code>
<code>package org.springframework.context.annotationX.circular.autowired;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Spring  @Autowired DI  循环依赖  Bean2 Demo
 */
@Component
public class Bean2AutowiredBean1Demo {

    @Autowired
   private Bean1AutowiredBean2Demo bean1;

    public void hello(){
        System.out.println("Run Circular Dependency Success");
    }
}/<code>

两种 DI 方式的单元测试代码

<code>package org.springframework.context;


import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotationX.circular.autowired.Bean1AutowiredBean2Demo;
import org.springframework.context.annotationX.circular.constructor.Bean1ConstructorBean2Demo;

/**
 * Created by 以斗争求团结则团结存,以退让求团结则团结亡 !
 */
public class AnnotationCircularDependencyTestX {

    @Test
    public void diBeanByAutowired() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.springframework.context.annotationX.circular.autowired");
        context.refresh();
        Bean1AutowiredBean2Demo bean1 = (Bean1AutowiredBean2Demo) context.getBean("bean1AutowiredBean2Demo");
        bean1.hello();
    }

    @Test
    public void diBeanByConstructor () throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.springframework.context.annotationX.circular.constructor");
        context.refresh();
        Bean1ConstructorBean2Demo bean1 = (Bean1ConstructorBean2Demo) context.getBean("bean1ConstructorBean2Demo");
        bean1.hello();
    }
}/<code>

猜猜上面那种 DI 方式打印了 "Run Circular Dependency Success" 以及它解决循环依赖的方式 ?

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

答案: 注解自动装配 DI 示例代码 打印成功 而 构造器 DI 示例代码因为循环依赖运行失败 , 那这两种方式有什么区别呢 !

(构造器 DI 错误日志)

<code> Unsatisfied dependency expressed through constructor parameter 0; nested exception is
 org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name
 'bean2ConstructorBean1Demo' defined in file
 [D:\SpringFamily-SourceCodeStudy\Spring-Framework\spring-framework-5.1.6.REL
 EASE\spring-context\out\test\classes\org\springframework\context\annotationX\circular\constructor\Bean2Const
 ructorBean1Demo.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is
 org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name
 'bean1ConstructorBean2Demo': Requested bean is currently in creation: Is there an unresolvable circular
 reference?

 at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
    ..../<code>
  • 注解自动装配 DI 方式 优点: 基于三层缓存不会发生循环依赖 自描述清晰 缺点: 对构建单元测试不友好
  • 构造器 DI 方式 优点: 代码结构明确,可读性高 构建单元测试友好 非IOC容器环境可使用new实例化该类的对象。 缺点: 会发生循环依赖 当注入参数较多时,代码臃肿。

对于循环依赖问题,Spring根据注入方式,采取不同的处理策略,如果依赖双方都是使用属性值注入或者Setter方法注入,则Spring可以自动解决循环依赖注入问题,Spring 程序可以成功启动;如果依赖双方是使用构造函数注入对方或者主Bean对象使用构造函数注入或循环注入的Bean都是原型模式

,则Spring 无法解决循环依赖注入 ,Spring程序报循环依赖无法启动。

注解 DI 方式 的运行成功原因

注解 DI 方式与 构造器 DI 方式 最终要达到的目的相同, 但Spring 对它俩的实现却不太一样, Spring-Context 在 AbstractApplicationContext.refresh() 方法完成 Bean 的关键生命周期 IOC, 实例化, DI 等, DI 具体是 IOC 完成后调用 finishBeanFactoryInitialization() 方法, 具体方法逻辑如下

  • 能触发依赖注入的条件有俩: 1. 第一次调用 getBean 方法时, 2. 懒加载被预实例化时, 此方法满足了其中第一条.
  • 1.根据 beanDefinitionMap 依次判断 Bean 是否 Lazy, 是否 Prototype, 是否 Abstract 等等
  • 2.接下来根据判断结果 填充构造方法来反射 Bean 的从而实例化. 所以在此之前必须推断Bean的构造方法.
  • 3.反射实例化一个对象;注意我这里说的是对象、对象、对象;不是并不是一个完整的bean,因为 对象属性是没有注入,所以不是一个完整的bean;
  • 4.Spring 处理 合并后的 BeanDefinition.
  • 5.判断是否支持 循环依赖 如果支持则提前把 一个工厂存入 singletonFactories Map>
  • 6.进行属性注入
  • 7.回调 Aware 接口, 生命周期回调方法, 是否需要代理
  • 8.put 到 Spring容器
  • 文章最后会带大家详细阅读上述源码.
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

成功原因:

<code>// 是否需要提前曝光,用来解决循环依赖时使用
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");
    }
    // 这里是一个匿名内部类, 为了循环引用, 尽早持有对象的引用    
    // 解决循环依赖 第二个参数是回调接口,实现的功能是将切面动态织入 bean
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

protected void addSingletonFactory(String beanName, ObjectFactory> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            // 判断 singletonObjects 不存在 beanName
            if (!this.singletonObjects.containsKey(beanName)) {
            // 注释 5.4 放入 beanName -> beanFactory,到时在 getSingleton() 获取单例时,可直接获取创建对应 bean 的工厂,解决循环依赖
            this.singletonFactories.put(beanName, singletonFactory);
            // 从提前曝光的缓存中移除,之前在 getSingleton() 放入的
            this.earlySingletonObjects.remove(beanName);
            // 往注册缓存中添加 beanName
            this.registeredSingletons.add(beanName);
        }
    }
}
/<code> 

先来看 earlySingletonExposure 这个变量: 从字面意思理解就是需要提前曝光的单例

有以下三个判断条件:

  • mbd 是否是单例
  • 该容器是否允许循环依赖
  • 判断该 bean 是否在创建中。

如果这三个条件都满足的话,就会执行 addSingletonFactory 操作。要想着,写的代码都有用处,所以接下来看下这个操作解决的什么问题和在哪里使用到吧

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

A 类中含有属性 B,B 类中含有属性 A,这两个类在初始化的时候经历了以下的步骤:

  1. 创建 Bean1AutowiredBean2Demo,先记录对应的 beanName 然后将 Bean1AutowiredBean2Demo的创建工厂 beanFactoryA 放入缓存中
  2. 对 Bean1AutowiredBean2Demo的属性填充方法 populateBean,检查到依赖 Bean2AutowiredBean1Demo,缓存中没有 Bean2AutowiredBean1Demo 的实例或者单例缓存,于是要去实例化 Bean2AutowiredBean1Demo。
  3. 开始实例化 Bean2AutowiredBean1Demo,经历创建 Bean1AutowiredBean2Demo的过程,到了属性填充方法,检查到依赖了 Bean1AutowiredBean2Demo。
  4. 调用 getBean(Bean1AutowiredBean2Demo) 方法,在这个函数中,不是真正去实例化 Bean1AutowiredBean2Demo,而是先去检测缓存中是否有已经创建好的对应的 bean,或者已经创建好的 beanFactory
  5. 检测到 beanFactoryA 已经创建好了,而是直接调用 ObjectFactory 去创建 Bean1AutowiredBean2Demo
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

构造器 DI 方式 运行失败的原因

构造方法DI 抛出异常前调用堆栈信息

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

失败原因: 根据上述堆栈可以分析, autowireConstructor() 试图通过构造方法反射 bean1ConstructorBean2Demo 实例时它必须先实例化 bean2ConstructorBean1Demo 然后依次循环, 走到 getSingleton() -> DefaultSingletonBeanRegistry.beforeSingletonCreation() 方法时就检测出异常, 那么为什么这种方式没有像 注解 DI 那样解决问题呢 ?

  • 注解DI方式 与 构造器DI方式最大的区别在与 AbstractAutowireCapableBeanFactory.createBeanInstance() 中的实例化策略不太一样. 从各自定义SpringBean的源代码上看, 构造器DI方式 需要申明当前类的构造器以及依赖的类, 而 注解DI方式则不需要 (默认空参)
  • 构造器DI: return autowireConstructor(beanName, mbd, ctors, args); 使用容器的自动装配特性, 调用匹配的构造方法进行实例化
  • 注解DI: return instantiateBean(beanName, mbd); 使用默认的无参构造方法进行实例化
  • 如上图所示, 调用堆栈 在 createBeanInstance() 实例化方法中发生了循环引用, 并没有执行到 populateBean()进行依赖注入. 为什么会发生这一切?

在此之前建议阅读一下 Spring官方对循环依赖的文档

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

DI时 thorw BeanCurrentlyInCreationException 代码片段

<code>// 构造方法DI getSingleton() 中 thorw BeanCurrentlyInCreationException
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // 当前 Bean 不存在可排除的 inCreationCheckExclusions && 当前 Bean 之前已存在于 则 thorw singletonsCurrentlyInCreation 中
    protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

    protected void afterSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
    }
}
/<code>

构造方法DI thorw 的触发原因: 两次 beforeSingletonCreation() 同一个Bean, 因为如果是没有发生循环依赖的话接下来会执行 afterSingletonCreation(beanName) 清除本轮 singletonsCurrentlyInCreation.remove(beanName) 但在 beforeSingletonCreation--> 递归 autowireConstructor()

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

<code>// 原型BeanDI doGetBean 中 thorw BeanCurrentlyInCreationException
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    protected  T doGetBean(final String name, @Nullable final Class requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

      // 如果之前创建过相同的原型Bean 则 thorw
        if (isPrototypeCurrentlyInCreation(beanName)) {
          throw new BeanCurrentlyInCreationException(beanName);
        }

        /** 创建原型模式 Bean 的实例对象*/
         if (mbd.isPrototype()) {
            // 原型模式 (Prototype) 每次都会创建一个新的对象
            Object prototypeInstance = null;
        try {
            // 回调 beforePrototypeCreation() 方法, 默认的功能是注册当前创建的原型对象
            beforePrototypeCreation(beanName);
            // 创建指定 Bean 的对象实例
            prototypeInstance = createBean(beanName, mbd, args);
         }
            finally {
            // 回调 afterPrototypeCreation() 方法, 默认的功能是告诉 IOC 容器 不再创建指定 Bean 的原型对象
            afterPrototypeCreation(beanName);
                           }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
        ...
    }
} 

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    private final ThreadLocal prototypesCurrentlyInCreation =
            new NamedThreadLocal 
<>("Prototype beans currently in creation"); protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set>) curVal).contains(beanName)))); } protected void beforePrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String) { Set beanNameSet = new HashSet<>(2); beanNameSet.add((String) curVal); beanNameSet.add(beanName); this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set beanNameSet = (Set) curVal; beanNameSet.add(beanName); } } protected void afterPrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal instanceof String) { this.prototypesCurrentlyInCreation.remove(); } else if (curVal instanceof Set) { Set beanNameSet = (Set) curVal; beanNameSet.remove(beanName); if (beanNameSet.isEmpty()) { this.prototypesCurrentlyInCreation.remove(); } } } }/<code>

原型BeanDI thorw 的触发原因: 两次 beforePrototypeCreation() 同一个Bean, 因为如果是没有发生循环依赖的话接下来会执行 afterPrototypeCreation(beanName) 清除本轮 prototypesCurrentlyInCreation.remove() 但在 beforePrototypeCreation--> 递归 doGetBean()

回溯几个有意思的问题

Spring是如何发现循环依赖的?

巧妙的用了LeetCode[141]中 Set 解法 把Bean 的加载顺序当作一个单向链表边存入边判重.

Spring的注解DI方式 是如何解决循环依赖的 ?

因为使用 注解DI 代码风格上是没有构造函数的, 在AbstractAutowireCapableBeanFactory.createBeanInstance() 走空参构造进行实例化, 所以不需要去像构造器DI 那样去实例化别的类, 然后在 populateBean() 中进行属性注入, 这时候已经完成实例化了要进行依赖注入了, 构造器DI方式就是在 实例化的时候翻车的呀, 具体怎么进行循环依赖的属性注入就靠 二 三级缓存咯.

  • 一级缓存: singletonObjects 它是我们最熟悉的朋友,俗称“单例池”“容器”,缓存创建完成单例Bean的地方, 也可以称之为 Spring 容器.
  • 二级缓存: singletonFactories 映射创建Bean的原始工厂
  • 三级缓存: earlySingletonObjects 映射Bean的早期引用,也就是说在这个Map里的Bean不是完整的,甚至还不能称之为“Bean”,只是一个Instance.

千言万语都在gif图里, 感谢作者vt 授权...

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

修复构造器 DI 引发的循环依赖的补丁有那几种 ?

  • 在主构造DI 方法上加上 @Lazy, Spring会动态代理创建代理类来解决
  • 在发生循环依赖的注入主类上加上 @Autowired, 并记得删除构造函数
  • 实现 InitializingBean, ApplicationContextAware 接口, 在Spring 用 InitializingBean 时手动获取容器注入.
  • 更多

Spring Bean 是如何被创建的 ?

在学习 Spring 时你可以把它比作一家 糖果工厂 , 糖果工厂里很多条夹心软糖生产线, 其中最赚钱的两条夹心软糖生产线, 分别是A生产线 与X生产线, A生产线生产软糖要必备一种叫@注解的糖浆原料, X 生产线则要必备另一种叫

两种软糖的初体验

<code>import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SoftSweetsTest {

    @Test
    public void A_ProductLine() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.springframework.context.softsweetsX");
        context.refresh();
        SoftSweetsBean bean = (SoftSweetsBean) context.getBean("softSweetsBean");
        System.out.println("\n新鲜出炉的A软糖 ~~~ \n 生产线名称: " + bean.getProductionLineName() + "\n 生产日期: " + bean.getDateManufacture());
    }

    @Test
    public void X_ProductLine() {
        // test-resources
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("org/springframework/beans/factory/xml/SoftSweetsX.xml");
        SoftSweetsBean bean = (SoftSweetsBean) context.getBean("softSweetsBean");
        System.out.println("\n新鲜出炉的X软糖 ~~~ \n 生产线名称: " + bean.getProductionLineName() + "\n 生产日期: " + bean.getDateManufacture());
    }
}/<code>

控制台输出结果

<code>新鲜出炉的X软糖 ~~~ 
 生产线名称: org.springframework.context.support.ClassPathXmlApplicationContext@525b461a
 生产日期: 2020-05-28T13:57:23.738+08:00[Asia/Shanghai]

新鲜出炉的A软糖 ~~~ 
 生产线名称: org.springframework.context.annotation.AnnotationConfigApplicationContext@10db82ae
 生产日期: 2020-05-28T13:57:24.784+08:00[Asia/Shanghai]/<code> 

如果你对生产软糖感兴趣 来吧 -> SpringFamily-SourceCodeStudy

Bean 加载步骤

  • IOC (Inversion of Control 控制反转) 定位 (确定原料位置) 加载 (找到原料后提取为可注册 BeanDefinition) 注册 (将 BeanDefinition 校验后注册到 Map beanDefinitionMap)
  • DI (Dependency Injection 依赖注入) 实例化 (反射 new 对象)ioc 依赖注入 (容器主动查找 bean 依赖)

IOC 控制反转

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

两条生产线的 定位与 加载 代码

<code>// X 生产线
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    public ClassPathXmlApplicationContext(
                String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
                throws BeansException {
            // 设置容器资源加载器
            super(parent);
            /*   将配置的Bean信息为 Spring 封装的 Resource */
            setConfigLocations(configLocations);
            if (refresh) {
                refresh();
            }
        }

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 创建 XmlBeanDefinitionReader, 即创建 Bean 读取器
        //  并通过回调设置到容器中, 容器使用该读取器读取 Bean 配置资源
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // 为 Bean 读取器设置 Spring 资源加载器
        // AbstractXmlApplicationContext 的祖先父类 AbstractApplicationContext 继承 DefaultResourceLoader
        // 因此容器本身也是一个资源加载器
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        // 为Bean 读取器设置 SAX xml 解析器
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // 当Bean 读取器读取 Bean 定义 xml 资源文件时, 启用 xml 的校验机制
        initBeanDefinitionReader(beanDefinitionReader);
        // Bean 读取器真正实现加载的方法
        loadBeanDefinitions(beanDefinitionReader);
    }
}

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

            // 按照 Spring 的Bean 语义要求将 Bean 配置信息解析并转换为容器内部数据结构
        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            /* 得到 BeanDefinitionDocumentReader 来对 XML 格式的 BeanDefinition 进行解析*/
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            // 获得容器中注册的 Bean 总数 (包含内置 bean)
            int countBefore = getRegistry().getBeanDefinitionCount();
            // 解析过程的入口, 这里使用了委派模式, BeanDefinitionDocumentReader 只是一个接口
            /*  具体的解析过程由实现类 DefaultBeanDefinitionDocumentReader 完成 */
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            // 统计解析的 Bean 数量
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }
    }
}

// ----------------------------------------------- 分割线 ---------------------------------------------------

// A 生产线
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    public void scan(String... basePackages) {
            Assert.notEmpty(basePackages, "At least one base package must be specified");
            /*  */
            this.scanner.scan(basePackages);
    }
}

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

    public int scan(String... basePackages) {
        // 获得容器中注册的 Bean 总数 (包含内置 bean)
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

        doScan(basePackages);

        // Register annotation config processors, if necessary.
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }

       // 统计解析的 Bean 数量
        return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }

       protected Set doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set beanDefinitions = new LinkedHashSet<>();
        for (String basePackage : basePackages) {
            /*  */
            Set candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder =
                            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    /*  */
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

}
/<code>

上述代码 表示 两条生产线定位 载入 是不同的, 但从 UML 类图看 它俩 都继承了 AbstractApplicationContext 所以 注册 DI 是相同的

<code>public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    // 存储注册信息 BeanDefinition
    private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

        @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        // 校验解析的 beanDefinition
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {
                // 注册的过程中需要线程同步, 以保证数据的一致性
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        // 检查是否已经注册过同名的 beanDefinition
        if (existingDefinition != null || containsSingleton(beanName)) {
            // 重置所有已经注册过的 beanDefinition 缓存
            resetBeanDefinition(beanName);
        }
    }
}    /<code>

总揽全局, 可以看到我们讲的 IOC 与 DI 只是众多 Spring 生命周期中的一部分.

<code>public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 1. 调用容器准备的刷新方法, 获取容器的当前时间, 同时给容器设置同步标识
            prepareRefresh();

            // 2.  告诉子类启动 refreshBeanFactory()方法, Bean定义资源文件的载入从子类的 refreshBeanFactory() 方法启动
            // 继承了 AbstractRefreshableApplicationContext 的容器子类可以调用, 从 UML 图上看 X 生产线可以,A 生产线不行
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 3. 为 BeanFactory 配置容器特性, 例如类加载器, 事件处理器等
            prepareBeanFactory(beanFactory);

            try {
                // 4. 为容器的某些子类指定的特殊的 Post 事件处理器
                postProcessBeanFactory(beanFactory);

                // 5.  调用所有注册的 BeanFactoryPostProcessor 的 Bean
                invokeBeanFactoryPostProcessors(beanFactory);

                // 6. 为 BeanFactory 注册 Post 事件处理器
                // BeanPostProcessor 是Bean 后置处理器, 用于监听容器触发的事件
                registerBeanPostProcessors(beanFactory);

                // 7. 初始化信息源, 和国际化相关
                initMessageSource();

                // 8. 初始化容器事件传播器
                initApplicationEventMulticaster();

                // 9. 调用子类的某些特殊的Bean的初始化方法
                onRefresh();

                // 10. 为事件传播器注册事件监听器
                registerListeners();

                // 11.  初始化所有剩余的单例模式Bean (non-lazy-init)
                finishBeanFactoryInitialization(beanFactory);

                // 12. 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 13. 销毁已经创建的单例Bean,以避免挂起资源。
                destroyBeans();

                // 14. 取消刷新操作, 重置容器的同步标识
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // 15. 重设公共缓存, 可能再也不需要单例bean的元数据了……
                resetCommonCaches();
            }
        }
    }    
}/<code>

DI 依赖注入

闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

循环依赖就发生在 DI 依赖注入这一步. 接下来我们详细探讨一下 它的原理. 看千遍不如手动搞一遍, 不然只是别人的知识,

依赖注入触发规则

  • 用户第一次调用 getBean 方法时, IOC 容器触发依赖注入
  • Bean 设置为 懒加载, 在需要预实例化 Bean 时触发依赖注入
闷棍暴打面试官 Spring源码系列:(一) Spring 如何解决循环依赖

<code>public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {

   // 11.  初始化所有剩余的单例模式Bean (non-lazy-init)
   protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ...
       beanFactory.preInstantiateSingletons();
    }   
}

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    @Override
    public void preInstantiateSingletons() throws BeansException {

        List beanNames = new ArrayList<>(this.beanDefinitionNames);

        // 触发所有非惰性单例bean的实例化…
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {
                    ... 
                }
                else {
                    //  第一次调用 getBean 方法时, IOC 容器触发当前 Bean的依赖注入与实例化
                    getBean(beanName);
                }
            }
        }
        ...
    }
}


public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

        protected  T doGetBean(final String name, @Nullable final Class requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

            // 根据指定的名称获取被管理的 Bean 名称, 剥离指定名称中对容器的相关依赖
            // 如果指定的是别名, 将别名转换为 规范的 Bean 名称
            final String beanName = transformedBeanName(name);
            Object bean;

            // 先从缓存中读取是否已经有被创建过的单例模式的 Bean
            // 对于单例模式的Bean 整个 IOC 容器中只创建一次, 不需要重复创建
            Object sharedInstance = getSingleton(beanName);
            // IOC 容器创建单例模式的 Bean 示例对象
            if (sharedInstance != null && args == null) {
                if (logger.isTraceEnabled()) {
                    // 如果在容器中已有指定名称的单例模式 Bean 被创建, 直接返回已经创建的 Bean
                    if (isSingletonCurrentlyInCreation(beanName)) {
                        logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                                "' that is not fully initialized yet - a consequence of a circular reference");
                    }
                    else {
                        logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                    }
                }
                // 注意: FactoryBean 是创建对象的工厂 Bean, BeanFactory 是管理 Bean 的工厂
                // 获取给定 Bean 的实例对象, 主要完成 FactoryBean 的相关处理
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }

            else {
                // 缓存中没有正在创建的 单例模式的 Bean
                // 缓存中已有原型模式的 Bean
                // 但是由于循环依赖导致实例化对象失败
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }

                // 对 IOC 容器中是否存在指定名称的 BeanDefinition 进行检查
                // 首先检查是否能对当前的 BeanFactory 中获取所需要的 Bean,
                // 如果不能则委托当前容器的父容器去查找, 如果还是找不到则沿着容器的继承体系向父容器查找
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    // 解析指定 Bean 名称的原始名称
                    String nameToLookup = originalBeanName(name);
                    if (parentBeanFactory instanceof AbstractBeanFactory) {
                        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                                nameToLookup, requiredType, args, typeCheckOnly);
                    }
                    else if (args != null) {
                        // 委托父容器根据指定名称和显式的参数查找
                        return (T) parentBeanFactory.getBean(nameToLookup, args);
                    }
                    else if (requiredType != null) {
                        // 委托父容器根据指定 名称和类型查找
                        return parentBeanFactory.getBean(nameToLookup, requiredType);
                    }
                    else {
                        // 委托父容器根据指定 名称查找
                        return (T) parentBeanFactory.getBean(nameToLookup);
                    }
                }

                // 创建的 Bean 是否需要进行类型验证, 一般不需要
                if (!typeCheckOnly) {
                    // 向容器标记指定的 Bean 已经被创建
                    markBeanAsCreated(beanName);
                }

                try {
                    // 根据指定 Bean 名称获取其父级 Bean 定义
                    // 主要解决 Bean 继承子类和父类公共属性问题
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);

                    // 获取当前 Bean 所有依赖 Bean 的名称
                    String[] dependsOn = mbd.getDependsOn();
                    /** 如果当前 Bean 有 @DependsOn 依赖的 Bean */
                    if (dependsOn != null) {
                        for (String dep : dependsOn) {
                            if (isDependent(beanName, dep)) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                            }
                            // 把被依赖 Bean 注册给当前依赖的 Bean
                            registerDependentBean(dep, beanName);
                            try {
                                // 递归调用 getBean()方法, 获取给当前依赖 Bean
                                getBean(dep);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                            }
                        }
                    }

                    /** 创建单例模式的 Bean 的实例对象*/
                    if (mbd.isSingleton()) {
                        // 这里使用了一个匿名的内部类创建 Bean 实例对象, 并且注册给所依赖的对象
                            sharedInstance = getSingleton(beanName, () -> {
                                try {
                                    // 创建一个指定的 Bean 的实例对象, 如果有父级继承, 则会合并子类和父类的定义
                                    return createBean(beanName, mbd, args);
                                }
                                catch (BeansException ex) {
                                    // Explicitly remove instance from singleton cache: It might have been put there
                                    // eagerly by the creation process, to allow for circular reference resolution.
                                    // Also remove any beans that received a temporary reference to the bean.
                                    // 显式地从容器中单例模式的 Bean 缓存中清除实例对象
                                    destroySingleton(beanName);
                                    throw ex;
                                }
                            });
                        // 获取给定的 Bean 实例对象
                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                    }

                    /** 创建原型模式 Bean 的实例对象*/
                    else if (mbd.isPrototype()) {
                        // 原型模式 (Prototype) 每次都会创建一个新的对象
                        Object prototypeInstance = null;
                        try {
                            // 回调 beforePrototypeCreation() 方法, 默认的功能是注册当前创建的原型对象
                            beforePrototypeCreation(beanName);
                            // 创建指定 Bean 的对象实例
                            prototypeInstance = createBean(beanName, mbd, args);
                        }
                        finally {
                            // 回调 afterPrototypeCreation() 方法, 默认的功能是告诉 IOC 容器 不再创建指定 Bean 的原型对象
                            afterPrototypeCreation(beanName);
                        }
                        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                    }

                    /**  创建 Web Bean 的实例对象, 比如 request , session, application 等生命周期*/
                    else {
                        // 要创建的 Bean 既不是单例模式的, 也不是原型模式的, 则根据 Bean 定义资源中
                        // 配置的生命周期范围, 选择实例化 Bean 的合适方法, 这种方式在多用于 Web 应用程序中
                        String scopeName = mbd.getScope();
                        final Scope scope = this.scopes.get(scopeName);
                        // 如果Bean 定义资源中没有配置生命周期范围, 则Bean定义不合法
                        if (scope == null) {
                            throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                        }
                        try {
                            // 这里又使用了一个匿名内部类, 获取一个指定生命周期范围的实例
                            Object scopedInstance = scope.get(beanName, () -> {
                                beforePrototypeCreation(beanName);
                                try {
                                    return createBean(beanName, mbd, args);
                                }
                                finally {
                                    afterPrototypeCreation(beanName);
                                }
                            });
                            // 获取指定 Bean 的实例对象
                            bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                        }
                        catch (IllegalStateException ex) {
                            ....
                        }
                    }
                }
                catch (BeansException ex) {
                    cleanupAfterBeanCreationFailure(beanName);
                    throw ex;
                }
        }
...

        return (T) bean;
    }
}

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // 封装被创建的 Bean 对象
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        // 获取实例化对象的类型
        Class> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // 调用 PostProcessor 后置处理器
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                ...
                }
                mbd.postProcessed = true;
            }
        }

        //  向容器中 缓存单例模式的 Bean 对象, 以防止循环引用
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            // 这里是一个匿名内部类, 为了循环引用, 尽早持有对象的引用
            // 第二个参数是回调接口,实现的功能是将切面动态织入 bean
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Bean 对象的初始化, 依赖注入在此触发
        Object exposedObject = bean;
        try {
            // 将 Bean 实例对象封装, 并且将 Bean 定义中配置的属性值赋给实例对象
            populateBean(beanName, mbd, instanceWrapper);
            // 调用初始化方法,例如 init-method
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            // 获取指定名称的已注册的单例模式 Bean 对象
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                // 根据名称获取 的已注册的 Bean 和正在实例化的 Bean 是同一个
                if (exposedObject == bean) {
                    // 当前实例化的 Bean 初始化完成
                    exposedObject = earlySingletonReference;
                }
                // 当前 Bean 依赖其他 Bean, 并且当发生循环引用时不允许创建新的实例对象
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set actualDependentBeans = new LinkedHashSet 
<>(dependentBeans.length); // 获取当前 Bean 所依赖的其他 Bean for (String dependentBean : dependentBeans) { // 对依赖 Bean 进行类型检查 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { ... } } } } // 注册完成依赖注入的 Bean try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }/<code>

后话

Mason 能看懂源码,主要有两方面在起作用,

一方面是因为水滴石穿的不懈努力,客观上起了作用,

一方面是因为 Mason 通过读毛选掌握了克服困难的方法论, 主观上起了作用,

推荐大家参加 毛三公的B站活动 #我在读毛选#


分享到:


相關文章: