一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 26 天,点击查看活动详情
日积月累,水滴石穿 😄
问题:什么是循环依赖呢?
就是一个或者多个 bean 之间互相引用对方,这种依赖关系最终形成一个闭环就是循环依赖。循环依赖有这以下几种情况:
- 自己依赖自己
- 两个对象互相依赖
- 多个对象间接依赖
问题:循环依赖有几种场景呢?
构造器注入
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 的生成步骤如下:
可以看到,对于 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 也创建不出来。
简化一下生命周期,将重要的部分列出来:
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
多了一个early
,early 早期
,用于保存实例化完成的 bean 实例,Bean的生命周期还没走完就把这个 Bean 实例放入了earlySingletonObjects
中,属于半成品对象。 - singletonFactories:三级缓存,缓存的是
ObjectFactory
,表示对象工厂,用来创建某个对象的。主要是解决 Spring AOP。
问题:一定要三级缓存吗?
就上述出现的循环依赖,一定要用三级缓存才能解决吗?再增加一个 Map 不就解决了吗?一个缓存用于存放成品对象,另外一个缓存用于存放半成品对象。
没有 AOP 的循环依赖
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 的代理对象。造成两者不一致了,正常情况需如下:
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中添加一个 key
为 beanName
,value
为 ObjectFactory
的数据。然后从 二级缓存 earlySingletonObjects 删除 key
为beanName
的数据。再然后将 beanName
放入 registeredSingletons
的Set
集合中。这段代码重点就是往 第三级缓存里添加了一个 key
为 beanName
,value
为 ObjectFactory的函数式接口
,也就是一个 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
接口放入到了三级缓存中了。然后调用 singletonFactory
的getObject()
,也就是执行 lambda
体。我们现在可以知道 lambda
体是在产生循环依赖的时候才会被执行。然后将获得的对象保存在二级缓存中,将三级缓存的记录进行删除。
lambda
体执行完毕之后,会返回一个对象。那该对象一定是 代理对象 吗?
执行 lambda
体,也技术执行getEarlyBeanReference
方法。 进入AbstractAutowireCapableBeanFactory
类getEarlyBeanReference
方法,
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
拼接上 &
。
第二行往 earlyProxyReferences
Map容器里添加了一条记录,key
为cacheKey
的值,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()))));
}
- 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。