Spring源码(十三)-Spring 是如何解决循环依赖的

552 阅读24分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 26 天,点击查看活动详情

日积月累,水滴石穿 😄

问题:什么是循环依赖呢?

就是一个或者多个 bean 之间互相引用对方,这种依赖关系最终形成一个闭环就是循环依赖。循环依赖有这以下几种情况:

  • 自己依赖自己

image-20210517211457252.png

  • 两个对象互相依赖

image-20210517211645932.png

  • 多个对象间接依赖

image-20210517211606037.png

问题:循环依赖有几种场景呢?

构造器注入

public class A {

	private B b;
	//通过构造方法注入 B
	public A(B b) {
		System.out.println("b" + b);
	}
	public void test(){
		System.out.println("属性B = " + b);
	}
}

public class B {

	private A a;
    //通过构造方法注入 A
	public B(A a) {
		System.out.println("a" + a);
	}

	public void test(){
		System.out.println("属性A = " + a);
	}
}

xml配置
<bean class="com.gongj.circularDependencies.dto.A" id="a">
	<constructor-arg index="0" ref="b"></constructor-arg>
</bean>
<bean class="com.gongj.circularDependencies.dto.B" id="b">
	<constructor-arg index="0" ref="a"></constructor-arg>
</bean> 
  • 启动类
public static void main(String[] args) {
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("circularDependencies.xml");
	A a = (A)context.getBean("a");
	a.test();
}
结果:
 抛出 BeanCreationException 异常

单例的 setter 注入

public class A {

	private B b;

	public B getBb() {
		return b;
	}

	public void setBb(B b) {
		this.b = b;
	}

	public void test(){
		System.out.println("属性B = " + b);
	}
}


public class B {
	private A a;
    
	public A getAa() {
		return a;
	}

	public void setAa(A a) {
		this.a = a;
	}

	public void test(){
		System.out.println("属性A = " + a);
	}
}

xml配置:
    <bean class="com.gongj.circularDependencies.dto.A" id="a">
		<property name="bb" ref="b"></property>
	</bean>
	<bean class="com.gongj.circularDependencies.dto.B" id="b">
		<property name="aa" ref="a"></property>
	</bean>

结果:
属性B = com.gongj.circularDependencies.dto.B@19d37183

depends-on指定依赖

	<bean class="com.gongj.circularDependencies.dto.A" id="a" depends-on="b">
		<property name="bb" ref="b"></property>
	</bean>
	<bean class="com.gongj.circularDependencies.dto.B" id="b" depends-on="a">
		<property name="aa" ref="a"></property>
	</bean>
            
结果:
抛出 BeanCreationException 异常

原型的 setter 注入

<bean class="com.gongj.circularDependencies.dto.A" id="a" scope="prototype">
		<property name="bb" ref="b"></property>
	</bean>
	<bean class="com.gongj.circularDependencies.dto.B" id="b" scope="prototype">
		<property name="aa" ref="a"></property>
	</bean>
        
结果:
抛出 BeanCreationException 异常

从上面的几个例子可以得知:

对于构造器的循环依赖,Spring 是无法自动帮我们解决的,会抛出 BeanCurrentlyInCreationException 异常,表示循环依赖。当然可以由我们程序员解决,下面会讲到的。

Spring帮我们解决的循环依赖是 单例的 settet注入的循环依赖。对于作用域为 prototype 的循环依赖,Spring也是不会解决的,直接抛出 BeanCurrentlyInCreationException 异常。

使用 depends-on属性指定依赖,造成循环依赖,Spring 也不会对此进行解决,直接抛出 BeanCurrentlyInCreationException 异常 。

那么循环依赖是个问题吗?如果不考虑 Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情。那在 Spring 中为什么会有循环依赖这种问题产生呢?那是因为在 Spring 中,一个对象并不是简单 new 出来的,而是会经过一系列的 Bean的生命周期,就是因为 Bean 的生命周期所以才会出现循环依赖问题。当然,在 Spring 中,出现循环依赖的场景很多,有的场景 Spring 帮我们解决了,而有的场景则需要程序员来解决,下文详细来说Spring是如何解决循环依赖的,也就是为什么允许单例的 setter循环依赖注入

Bean的生命周期

这里不会对 Bean 的生命周期进行详细的描述,只描述一下大概的过程。想详细了解可以看看笔者前面的源码阅读。如果想真正的理解循环依赖,那对 Bean的生命周期 肯定要有了解的。

Bean 的生命周期指的就是:在 Spring 中,Bean 是如何生成的?

Bean 的生成步骤如下:

image.png

可以看到,对于 Spring 中的 Bean 的生成过程,步骤很多。

但可以发现,在 Spring 中,创建一个Bean,是在 实例化 这步得到的。推断构造方法之后根据构造方法反射得到一个对象的,当然还有其他方式得到一个对象,比如说工厂方法、Supplier 回调,不管其他方式如何创建,反正创建对象出来的这一步叫 实例化,而创建出来的这个对象我们称之为原始对象

得到一个原始对象后,Spring 需要给对象中的属性进行依赖注入,那么这个注入过程是怎样的?

比如上文说的 A 类,A 类中存在一个 B 类的 b 属性,所以,当 A类生成了一个原始对象之后,就会去给 b 属性去赋值,此时就会根据 b 属性的类型和属性名(beanName)去 BeanFactory 中去获取 B 类所对应的单例 bean。如果此时 BeanFactory 中存在 B 对应的 Bean,那么直接拿来赋值给 b 属性;如果此时 BeanFactory 中不存在 B 对应的 Bean,则需要生成一个 B 对应的 Bean,然后赋值给 b 属性。

问题就出现在第二种情况,如果此时 B 类在 BeanFactory 中还没有生成对应的 Bean,那么就需要去生成,就会经过 B 的 Bean 的生命周期。

那么在创建 B 类 Bean 的过程中, B 类中存在一个 A 类的 a 属性,那么在创建 B 类 Bean 的过程中就需要 A 类对应的 Bean,B类就会去创建 A,所以这里就出现了循环依赖:

A Bean 创建--> 依赖了B属性 --> 触发B Bean创建 --->B依赖了A属性--->需要A Bean(但A Bean还在创建过程中)

从而导致 A Bean 创建不出来,B Bean 也创建不出来。

image.png

简化一下生命周期,将重要的部分列出来:

A的生命周期
    1.实例化 A 对象(new A()),称之为 原始对象
    2.填充 b 属性(走getBean流程) --> 从单例池中获取对应的bean -->找不到 --> 创建 B 对应的 Bean(走B的生命周期)
    3.填充其他属性
    4.初始化后
    5.添加单例池
    
B的生命周期
    1.实例化 B 对象(new B()),称之为 原始对象
    2.填充 a 属性(走getBean流程) --> 从单例池中获取对应的bean -->找不到 --> 创建 A 对应的 Bean(走A的生命周期)
    3.填充其他属性
    4.初始化后
    5.添加单例池    

这就是循环依赖,但是上文说了, Spring 通过某些机制帮开发者解决了单例setter注入循环依赖的问题,这个机制就是 三级缓存

问题:什么是三级缓存?

Spring 使用三级缓存解决循环依赖!

  • singletonObjects:一级缓存,用于保存经历了完整生命周期的bean对象,也就是成品对象,最终给程序员使用的对象。
  • earlySingletonObjects:二级缓存,比 singletonObjects 多了一个 earlyearly 早期,用于保存实例化完成的 bean 实例,Bean的生命周期还没走完就把这个 Bean 实例放入了earlySingletonObjects中,属于半成品对象。
  • singletonFactories:三级缓存,缓存的是 ObjectFactory,表示对象工厂,用来创建某个对象的。主要是解决 Spring AOP。

问题:一定要三级缓存吗?

就上述出现的循环依赖,一定要用三级缓存才能解决吗?再增加一个 Map 不就解决了吗?一个缓存用于存放成品对象,另外一个缓存用于存放半成品对象。

没有 AOP 的循环依赖

image.png

A的生命周期
    1.实例化 A 对象(new A()),称之为原始对象 --> 原始对象放入 gongJMap<a,A原始对象> 中进行缓存
    2.填充 b 属性(走getBean流程) --> 从单例池中获取 b 对应的bean -->找不到 --> 创建 B 对应的 Bean(走B的生命周期)
    3.填充其他属性
    4.初始化后
    5.添加单例池
    
B的生命周期
    1.实例化 B 对象(new B()),称之为 原始对象 --> 原始对象放入 gongJMap<b,B原始对象> 中进行缓存
    2.填充 a 属性(走getBean流程) --> 从单例池中获取 a 对应的bean -->找不到 --> 去 gongJMap 获取 --> 得到A原始对象
    3.填充其他属性
    4.初始化后
    5.添加单例池   

可以看到 二级缓存 就能解决上述的循环依赖(不进行AOP时)。那 Spring 为什么要使用三级缓存呢?其实主要是 4.初始化后这步会可能进行 AOP 操作。AOP 操作会根据你的 原始对象 产生一个 代理对象 。生命周期再次发生变化,

需要进行 AOP

A的生命周期
    1.实例化 A 对象(new A()),称之为原始对象 --> 原始对象放入 gongJMap<a,A原始对象> 中进行缓存
    2.填充 b 属性(走getBean流程) --> 从单例池中获取 b 对应的bean -->找不到 --> 创建 B 对应的 Bean(走B的生命周期)
    3.填充其他属性
    4.初始化后(AOP)  -->产生代理对象
    5.添加单例池
    
B的生命周期
    1.实例化 B 对象(new B()),称之为 原始对象 --> 原始对象放入 gongJMap<b,B原始对象> 中进行缓存
    2.填充 a 属性(走getBean流程) --> 从单例池中获取 a 对应的bean -->找不到 --> 去 gongJMap 获取 --> 得到A原始对象
    3.填充其他属性
    4.初始化后(AOP) -->产生代理对象
    5.添加单例池   

各位可以思考一下上面这个步骤有没有问题?

1.实例化 A 对象(new A()),称之为原始对象 --> 原始对象放入 gongJMap<a,A原始对象> 中进行缓存
2.填充 b 属性(走getBean流程) --> 从单例池中获取 b 对应的bean -->找不到 --> 创建 B 对应的 Bean(走B的生命周期)
    
3.实例化 B 对象(new B()),称之为 原始对象 --> 原始对象放入 gongJMap<b,B原始对象> 中进行缓存
4.填充 a 属性(走getBean流程) --> 从单例池中获取 a 对应的bean -->找不到 --> 去 gongJMap 获取 --> 得到A原始对象
5.填充其他属性
6.初始化后(AOP) -->产生代理对象
7.添加单例池(将B代理对象放到单例池) B生命周期结束
    // 走 A 的生命周期  A 的 b 属性放的是 B 的代理对象
8.填充其他属性
9.初始化后(AOP)  -->产生代理对象
10.添加单例池 (将A代理对象放到单例池)

在第 4 步 进行填充 a 属性拿到的是 A 的原始对象。而在第 2 步 填充 b 属性,A 里的 b 属性放的是 B 的代理对象。造成两者不一致了,正常情况需如下:

image-20210520212102969.png

A 的 b 属性填充的是 B 的代理对象,B 的 a 属性填充的是 A 的代理对象。这才是正常的。那怎么解决呢!终于需要用到三级缓存了吗?不不不,还用不到,在这里还是可以使用二级解决的。办法:提前进行AOP处理,然后在初始化后那步进行判断,如果进行过 AOP 操作就不再进行AOP了。

A的生命周期
    1.实例化 A 对象(new A()),称之为原始对象 --> 提前进行AOP,产生代理对象--> 放入gongJMap<a,A代理对象> 中进行缓存
    2.填充 b 属性(走getBean流程) --> 从单例池中获取 b 对应的bean -->找不到 --> 创建 B 对应的 Bean(走B的生命周期)
    3.填充其他属性
    4.初始化后(AOP),判断是否进行过AOP了
    4.5 从gongJMap获取 A 的代理对象
    5.添加单例池(A代理对象)
    
B的生命周期
    1.实例化 B 对象(new B()),称之为 原始对象 --> 提前进行AOP,产生代理对象 --> 放入gongJMap<b,B代理对象> 中进行缓存
    2.填充 a 属性(走getBean流程) --> 从单例池中获取 a 对应的bean --> 找不到 --> 去 gongJMap 获取 --> 得到A代理对象
    3.填充其他属性
    4.初始化后(AOP),判断是否进行过AOP了
    4.5 从gongJMap获取 B 的代理对象
    5.添加单例池(B代理对象)

这种方式解决了A、B对象属性不一致的问题。那这里就会出现一个新的问题,什么情况下才需要提前进行 AOP 呢?答案是 产生循环依赖的时候才需要提前进行AOP。 因为如果没有出现循环依赖,A、B两个Bean各自走自己的生命周期那是不会有影响的。

A的生命周期
    1.实例化 A 对象(new A()),称之为原始对象 --> 原始对象放入 gongJMap<a,A原始对象> 中进行缓存
    2.填充属性
    3.初始化后(AOP)  --> 产生A代理对象
    4.添加单例池(A代理对象)
    
B的生命周期
    1.实例化 B 对象(new B()),称之为 原始对象 --> 原始对象放入 gongJMap<b,B原始对象> 中进行缓存
    2.填充属性
    3.初始化后(AOP) -->产生B代理对象
    4.添加单例池 (B代理对象)  

那又会有一个问题,我要才能怎么知道你产生了循环依赖呢?还是上述例子,A 依赖 B,B 依赖 A。在创建 A 的时候能知道有循环依赖吗?那肯定不能!填充 b 属性的时候?不能!实例化B?不能。只有在 B 实例化之后进行 a 属性填充时,才能知道 A、B发生了循环依赖。

解决:增加一个 Set 集合,用来存取正在创建的 beanName。生命周期再次发生变化,如下:

A的生命周期
    0.将 a 放入 Set 中
    1.实例化 A 对象(new A()),称之为原始对象
    2.填充 b 属性(走getBean流程) --> 从单例池中获取 b 对应的bean -->找不到 --> 创建 B 对应的 Bean(走B的生命周期)
    3.填充其他属性
    4.初始化后(AOP)
    4.5 从gongJMap获取 A 的代理对象
    5.添加单例池(A代理对象)
    
B的生命周期
    0.将 b 放入 Set 中
    1.实例化 B 对象(new B()),称之为 原始对象
    2.填充 a 属性(走getBean流程) --> 从单例池中获取 a 对应的bean --> 找不到 --> 判断 a 是否正在创建中 -->正在创建中,代表出现了循环依赖 --> gongJMap寻找--> 找不到 --> 进行AOP,产生代理对象 --> 得到A代理对象 --> gongJMap<a,A代理对象> 中进行缓存
    3.填充其他属性
    4.初始化后(AOP)
    4.5 从gongJMap获取 B 的代理对象
    5.添加单例池(B代理对象)

看到这,不知道各位有没有疑问,原始对象 我们没有将它缓存起来了。但前面又讲过,代理对象需要根据原始对象去创建。所以这时候才需要用到第三级缓存了

A的生命周期
    0.将 a 放入 Set 中,标记为当前单例bean正在创建中
    1.实例化 A 对象(new A()),称之为原始对象 -->放入第三级缓存<beanName:A原始对象>
    2.填充 b 属性(走getBean流程) --> 从单例池中获取 b 对应的bean --> 找不到 --> 判断 b 是否正在创建中(B没有在创建中) --> 创建 B 对应的 Bean(走B的生命周期)
    3.填充其他属性
    4.初始化后(AOP)
    4.5 从gongJMap获取 A 的代理对象
    5.添加单例池(A代理对象)
    
B的生命周期
    0.将 b 放入 Set 中,标记为当前单例bean正在创建中
    1.实例化 B 对象(new B()),称之为 原始对象 -->放入第三级缓存<beanName:B原始对象>
    2.填充 a 属性(走getBean流程) --> 从单例池中获取 a 对应的bean --> 找不到 --> 判断 a 是否正在创建中 --> 正在创建中,代表出现了循环依赖 --> 从 gongJMap 寻找--> 找不到 -->  从第三级缓存寻找 --> 得到A原始对象 --> 进行AOP,产生代理对象 --> 得到A代理对象 --> gongJMap<a,A代理对象> 中进行缓存
    3.填充其他属性
    4.初始化后(AOP)
    4.5 从gongJMap获取 B 的代理对象
    5.添加单例池(B代理对象)

到此,Spring 为什么要使用三级缓存去解决循环依赖的思路就到这了。接下来我们就开始阅读源码,看看 Spring 设计的是否与我们推断是否一致。

源码阅读

源码阅读呢会涉及到几个方法。我们根据上述所说的Bean的生命周期来分析。

第零步

该方法位于 DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)

创建 A 对象,首先从单例池拿,有直接返回。没有的话首先将 A 添加到正在创建Bean的集合中,然后进行创建 A 逻辑。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			//去单例池中获取实例
			Object singletonObject = this.singletonObjects.get(beanName);

			// 如果不存在实例,则创建单例bean实例
			if (singletonObject == null) {
				// 忽略。。。
				// 把当前正在创建的beanName添加到singletonsCurrentlyInCreation中,
				// singletonsCurrentlyInCreation是一个Set
				//表示这些bean正常创建中,在没创建完时不能重复创建
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// singletonFactory是外面传进来的lambda表达式,执行lambda表达式
					//就是调用 createBean()
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
                
				// 忽略。。。
                
				//将创建好的单例bean添加到单例池singletonObjects中
				//和单例注册表registeredSingletons中
				//并清除二级、三级缓存
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

protected void beforeSingletonCreation(String beanName) {
    // inCreationCheckExclusions中的beanName,表示如果是这些bean正在创建中,重复创建也没关系
    // singletonsCurrentlyInCreation中的beanName,表示这些bean正常创建中,在没创建完时不能重复创建
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

第一步

1.实例化 A 对象(new A()),称之为原始对象  ---> 放入第三级缓存<beanName,A原始对象>

关注一下 2、实例化,这里会产生一个原始对象。该方法位于AbstractAutowireCapableBeanFactory

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		//省略代码。。。。

		// 2、实例化
		if (instanceWrapper == null) {
			// 创建bean实例 1、工厂方法 2、构造函数自动注入 3、简单初始化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

		// 包装的实例对象,也就是原始对象
		final Object bean = instanceWrapper.getWrappedInstance();
		
		//省略代码。。。。

		//4、
		// 如果当前bean是单例并且支持循环依赖,且当前bean正在创建,
		//就通过往singletonFactories(三级缓存)添加一个objectFactory,
		//这样后期如果有其他bean依赖该bean 可以从singletonFactories获取到bean, 解决循环依赖
		// getEarlyBeanReference()可以对返回的bean进行修改,这边目前除了可能会返回 代理对象 其他的都是直接返回bean
		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");
			}
			// 构造一个 ObjectFactory 添加到singletonFactories中
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {

			// 5、
			// 填充属性 @Autowired,将各个属性注入
			// 对 bean 进行填充 将各个属性注入
			populateBean(beanName, mbd, instanceWrapper);

			// 6、
			// 执行初始化方法
			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);
			}
		}
		// 7、
		if (earlySingletonExposure) {
			// earlySingletonReference 只有在检测到有循环依赖的情况下才会不为空
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				// 如果提前暴露的对象(bean)和经过了完整的生命周期后的对象相等(exposedObject)
				// 则把缓存中的earlySingletonReference赋值给exposedObject
				// 最终会添加到singletonObjects中去
				// (初始化之后的bean等于原始的bean,说明不是proxy),
				//
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
			}
				//检测该bean的dependon的bean是否都已经初始化好了
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}

		return exposedObject;
	}

我们再关注一下第四点,该代码所处的位置 Bean进行实例化之后,属性填充之前。按照我们的理解是要放入到三级缓存的。

		//4、
		// 如果当前bean是单例并且支持循环依赖,且当前bean正在创建,
		//就通过往singletonFactories(三级缓存)添加一个objectFactory,
		//这样后期如果有其他bean依赖该bean 可以从singletonFactories获取到bean, 解决循环依赖
		// getEarlyBeanReference()可以对返回的bean进行修改,这边目前除了可能会返回动态代理对象 其他的都是直接返回bean
		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");
			}
			// 构造一个 ObjectFactory 添加到singletonFactories中
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

要不要往三级缓存添加对象是由 earlySingletonExposure这个变量控制的。三个值都为 true 时,earlySingletonExposure才为 true

  • mbd.isSingleton():当前 bean 是单例

  • allowCircularReferences:是否支持循环依赖,默认是 true

  • isSingletonCurrentlyInCreation(beanName):当前bean是否正在创建中,创建中则返回 true,至于在哪里被放入到 Set 集合中的,可以看前面的源码阅读。具体代码在DefaultSingletonBeanRegistry类的getSingleton方法。

``earlySingletonExposure这个变量的值,正常情况下都是为true的。 所以addSingletonFactory`方法都会被执行,那一起来看看它干了什么?

addSingletonFactory方法两个入参,一个是 beanName,一个是类型为 ObjectFactory的函数式接口。

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

如果 一级缓存 singletonObjects,也就是单例池中不存在当前beanName的记录,则进入if代码块。首先往 三级缓存 singletonFactories中添加一个 keybeanNamevalueObjectFactory 的数据。然后从 二级缓存 earlySingletonObjects 删除 keybeanName的数据。再然后将 beanName 放入 registeredSingletonsSet集合中。这段代码重点就是往 第三级缓存里添加了一个 keybeanNamevalueObjectFactory的函数式接口,也就是一个 Lambda 表达式。我们自己推断的只放一个原始对象。那我们来看看具体的 Lambda 表达式的实现!注意,这里并没有执行 Lambda 表达式的具体实现。可以看到这段代码比较符合我们所推测的,只不过Spring是往三级缓存里存的是 类型为 ObjectFactory 的 Lambda 表达式而不是纯粹原始对象

第二步

2、然后进行 b 属性填充 --> 从单例池中获取 b 对应的bean --> 找不到 --> 判断 b 是否正在创建中(B没有在创建中,还没开始创建呢) --> 创建 B 对应的 Bean。至于填充属性的详细过程本篇不再介绍,可以去看看小杰前面的文章。

最终会调用到 getBean(beanName)方法。然后进入到 doGetBean方法。

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

		// 对name进行转换,找到真正的beanName
		// 如果传入的name是"&gongjFactoryBean",那么beanName就是"gongjFactoryBean"
		final String beanName = transformedBeanName(name);
		Object bean;

		//根据beanName去单例池中获取Bean
		Object sharedInstance = getSingleton(beanName);  // Map<>
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				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 + "'");
				}
			}
			// 判断sharedInstance是不是FactoryBean,
			// 如果是FactoryBean,那么真正需要拿到的是getObject方法所返回的对象
			//beanName 是spinrg进行解析后获取到的BeanName  name 我们手动传入的beanName
			//sharedInstance 根据beanName获取到的单例Bean对象
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		//单例池没有获取到Bean 则走创建Bean的流程
		else {}

上述代码在本篇中只需要关注getSingleton方法。

@Override
@Nullable
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

注意getSingleton(beanName, true);的第二个参数值为 true

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从单例池中获取实例
    Object singletonObject = this.singletonObjects.get(beanName);

    // 如果从单例池中没有获取到实例 并且 指定的单例bean正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //锁定全局变量并进行处理
        synchronized (this.singletonObjects) {
            //earlySingletonObjects 二级缓存
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 没有从二级缓存中获取到 并且 allowEarlyReference 为 true
            if (singletonObject == null && allowEarlyReference) {
                // 实例化之后调用 addSingletonFactory 方法将
                // ObjectFactory 初始化存储在 singletonFactories Map中
                // singletonFactories 三级缓存
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 执行lambda AOp
                    singletonObject = singletonFactory.getObject();
                    //记录在缓存中 earlySingletonObjects与singletonFactories互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

从单例池获取 b Bean ,那是肯定获取不到的,所以 singletonObject值为 null。至于 b 是否正在创建中,那肯定也是 false,b 还没开始创建!所以 if代码块都不会进入,该方法直接返回 null。 返回 null 也就代表着 B 需要进行创建。进入到 B 的生命周期

第三步

开始创建 B Bean。流程如下:

0.将 b 放入 Set 中,标记为当前单例bean正在创建中
1.实例化 B 对象(new B()),称之为 原始对象 -->放入第三级缓存<beanName:B原始对象>
2.填充 a 属性(走getBean流程) --> 从单例池中获取 a 对应的bean --> 找不到 --> 判断 a 是否正在创建中 --> 正在创建中,代表出现了循环依赖 --> 从 gongJMap 寻找--> 找不到 -->  从第三级缓存寻找 --> 得到A原始对象 --> 进行AOP,产生代理对象 --> 得到A代理对象 --> gongJMap<a,A代理对象> 中进行缓存
//单例池没有获取到Bean 则走创建Bean的流程
else {
    // 省略
    // 根据Scope去创建bean
    //创建单例模式Bean的实例对象
    if (mbd.isSingleton()) {
        //使用一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
        sharedInstance = getSingleton(beanName, () -> {
            try {
                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;
            }
        });
        // sharedInstance可能是一个FactoryBean,如果是FactoryBean
        // 那么真正需要拿到的是getObject方法所返回的对象
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
}

关注一下 getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法,该方法与 第零步 一模一样。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			//去单例池中获取实例
			Object singletonObject = this.singletonObjects.get(beanName);

			// 如果不存在实例,则创建单例bean实例
			if (singletonObject == null) {
				// 忽略。。。
				// 把当前正在创建的beanName添加到singletonsCurrentlyInCreation中,
				// singletonsCurrentlyInCreation是一个Set
				//表示这些bean正常创建中,在没创建完时不能重复创建
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// singletonFactory是外面传进来的lambda表达式,执行lambda表达式
					//就是调用 createBean()
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
                
				// 忽略。。。
                
				//将创建好的单例bean添加到单例池singletonObjects中
				//和单例注册表registeredSingletons中
				//并清除二级、三级缓存
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

这里就会走 B 的生命周期了。进行实例化。

// singletonFactory是外面传进来的lambda表达式,执行lambda表达式
//就是调用 createBean()
singletonObject = singletonFactory.getObject();

进行完 B 的 实例化之后,然后进行填充属性。发现需要填充 A 属性,再走 A 的 getBean 方法。

既然是走 getBean 的方法,那就会进入到 第二步 所分析的 getSingleton方法。

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从单例池中获取实例
    Object singletonObject = this.singletonObjects.get(beanName);

    // 如果从单例池中没有获取到实例 并且 指定的单例bean正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //锁定全局变量并进行处理
        synchronized (this.singletonObjects) {
            //earlySingletonObjects 二级缓存
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 没有从二级缓存中获取到 并且 allowEarlyReference 为 true
            if (singletonObject == null && allowEarlyReference) {
                // 实例化之后调用 addSingletonFactory 方法将
                // ObjectFactory 初始化存储在 singletonFactories Map中
                // singletonFactories 三级缓存
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 执行lambda AOp
                    singletonObject = singletonFactory.getObject();
                    //记录在缓存中 earlySingletonObjects与singletonFactories互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

从单例池获取 a Bean 那是也是获取不到的,所以 singletonObject值为 null。至于 a 是否正在创建中,a 现在是在创建中了,所以进入if代码块,从二级缓存中获取实例,肯定获取不到,所以为 null,至于 allowEarlyReference的值,由上层传入 true。然后从三级缓存根据 beanName(也就是 a) 获取到 ObjectFactory类型的一个函数式接口。这时候是有值的,我们在 A 实例化之后,就将 key 为 a 的 ObjectFactory接口放入到了三级缓存中了。然后调用 singletonFactorygetObject(),也就是执行 lambda 体。我们现在可以知道 lambda 体是在产生循环依赖的时候才会被执行。然后将获得的对象保存在二级缓存中,将三级缓存的记录进行删除。

lambda 体执行完毕之后,会返回一个对象。那该对象一定是 代理对象 吗?

执行 lambda 体,也技术执行getEarlyBeanReference方法。 进入AbstractAutowireCapableBeanFactorygetEarlyBeanReference方法,

	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {  // AOP
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

先将原始对象赋予给另外一个变量。获得所有的BeanPostProcessor,判断是否是SmartInstantiationAwareBeanPostProcessor,如果是则执行 getEarlyBeanReference方法。将原始对象和 bean名称作为入参传入。

调试进入 SmartInstantiationAwareBeanPostProcessor类,可以发现getEarlyBeanReference方法下有两个子类实现。一个是InstantiationAwareBeanPostProcessorAdapter,另外一个是 AbstractAutoProxyCreator。这里我们看 AbstractAutoProxyCreator就好了,因为 InstantiationAwareBeanPostProcessorAdapter没有进行具体的实现。

进入AbstractAutoProxyCreator类,其实这时候我们可以发现该类所处的包路径为

org.springframework.aop.framework.autoproxy;,可以看到一个眼熟的词 aop

// 获取提前暴露的bean的引用,用来支持单例对象的循环引用,解决循环依赖问题	
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
	Object cacheKey = getCacheKey(bean.getClass(), beanName); 
	
	this.earlyProxyReferences.put(cacheKey, bean);

	return wrapIfNecessary(bean, beanName, cacheKey);  //可能会产生代理对象
}

该方法里有三行代码,我们一行一行的看。

  • getCacheKey
	protected Object getCacheKey(Class<?> beanClass, @Nullable String beanName) {
		if (StringUtils.hasLength(beanName)) {
			// isAssignableFrom:判断当前的 Class 所表示的类,
			// 是不是参数中传递的 Class 所表示的类的父类,超接口,或者是相同的类型
			// 是则返回true,否则返回false
			// 使用方式:父类.class.isAssignableFrom(子类.class)
			return (FactoryBean.class.isAssignableFrom(beanClass) ?
					BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
		}
		else {
			return beanClass;
		}
	}

首先判断当前beanName不等于 null 并且不等于空字符串,然后使用三元表达式计算当前 beanClass是否是FactoryBean子类或者子实现,如果是则将 beanName拼接上 &

第二行往 earlyProxyReferencesMap容器里添加了一条记录,keycacheKey的值,value原始对象。在生命周期初始化后那步就会根据``earlyProxyReferencesMap进行判断,是否进行过 AOP。

接下来我们看最重要的一个方法:wrapIfNecessary,方法名翻译之后大意是 如果需要包装,也就是说,如果要包装则产生代理对象,否则返回原对象。是否要产生代理对象是有条件的。

  • wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  // 在当前targetSourcedBeans中存在的bean,表示在实例化之前就产生了代理对象
  // 直接返回,那就不要再次产生代理对象了
  if(StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(
      beanName)) {
    return bean;
  }
  // advisedBeans 是一个 map, 存储的是 class:是否应该被代理,为true则需要被代理
  // 当前这个bean不用被代理
  if(Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
  }
  // 如果是普通bean,或者继承 Advisor、Pointcut、Advice
  //AopInfrastructureBean 的类不需要被代理
  if(isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(),
      beanName)) {
    // 将当前 cacheKey 标记为不用被代理
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
  }
  // 获取当前 beanClass 所匹配的 advisors
  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(),
    beanName, null);
  // 如果匹配的advisors不等于null,那么则进行代理,并返回代理对象
  if(specificInterceptors != DO_NOT_PROXY) {
    // 将当前 cacheKey 标记为 需要被代理
    this.advisedBeans.put(cacheKey, Boolean.TRUE);
    // 基于bean对象和Advisor创建代理对象
    Object proxy = createProxy(bean.getClass(), beanName,
      specificInterceptors, new SingletonTargetSource(bean));
    // 存一个代理对象的类型
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
  }
  this.advisedBeans.put(cacheKey, Boolean.FALSE);
  return bean;
}

上面 AOP 的逻辑走完了之后,就会将 A 对象进行返回,然后赋值给 B。B 的属性填充也就此完成,那就会继续往下走。

if (earlySingletonExposure) {
			// earlySingletonReference 只有在检测到有循环依赖的情况下才会不为空
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				// 如果提前暴露的对象(bean)和经过了完整的生命周期后的对象相等(exposedObject)
				// 则把缓存中的earlySingletonReference赋值给exposedObject
				// 最终会添加到singletonObjects中去
				// (初始化之后的bean等于原始的bean,说明不是proxy),
				//
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
			}
				//检测该bean的dependon的bean是否都已经初始化好了
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					/*
					* 因为 bean 创建后;其所依赖的 bean 一定是创建了的。
					* actualDependentBeans 不为空表示当 bean 创建后依赖的 bean 没有
					* 全部创建完,也就是说存在循环依赖
					*/
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}
try {
			// 8、注册DisposableBean
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
  • getSingleton:注意 allowEarlyReference的值为 false
@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 从单例池中获取实例
		Object singletonObject = this.singletonObjects.get(beanName);

		// 如果从单例池中没有获取到实例 并且 指定的单例bean正在创建中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			//锁定全局变量并进行处理
			synchronized (this.singletonObjects) {
				//earlySingletonObjects 二级缓存
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 没有从二级缓存中获取到 并且 allowEarlyReference 为 true
				if (singletonObject == null && allowEarlyReference) {
					//实例化之后调用 addSingletonFactory 方法将
					//ObjectFactory 初始化存储在 singletonFactories Map中
					// singletonFactories 三级缓存
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 执行lambda AOp
						singletonObject = singletonFactory.getObject();
						//记录在缓存中 earlySingletonObjects与singletonFactories互斥
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

又是这个方法,小杰带大家再来看看这个方法。这个时候 beanName 还是为 b,B 的生命周期还没走完呢。从单例池获取 -》 没有,b 还在创建中,所以进入 if,然后从二级里面获取 -》没有,allowEarlyReference由上层传入false,结束方法,返回 null。返回 null,就不会符合earlySingletonReference != null的判断,直接调用registerDisposableBeanIfNecessary方法,进行 Bean 销毁逻辑。

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
			if (mbd.isSingleton()) {
				// Register a DisposableBean implementation that performs all destruction
				// work for the given bean: DestructionAwareBeanPostProcessors,
				// DisposableBean interface, custom destroy method.
				registerDisposableBean(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
			else {
				// A bean with a custom scope...
				Scope scope = this.scopes.get(mbd.getScope());
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
				}
				scope.registerDestructionCallback(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
		}
	}

只要看 requiresDestruction方法就好了。

protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
		// 判断某个Bean是否拥有销毁方法
		// 1. 实现了DisposableBean接口或AutoCloseable接口
		// 2. BeanDefinition中定义了destroyMethodName
		// 3. 类中是否存在@PreDestroy注解的方法
		return (bean.getClass() != NullBean.class &&
				(DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&
						DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
	}

  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。