Spring源码系列文章
Spring源码解析(一):环境搭建
Spring源码解析(二):bean容器的创建、默认后置处理器、扫描包路径bean
Spring源码解析(三):bean容器的刷新
Spring源码解析(四):单例bean的创建流程
Spring源码解析(五):循环依赖
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
依赖情况 | 依赖注入方式 | 循环依赖是否被解决 |
---|---|---|
AB相互依赖(循环依赖) | 均采用setter方法注入 | 是 |
AB相互依赖(循环依赖) | 均采用构造器注入 | 否 |
AB相互依赖(循环依赖) | A中注入B的方式为setter方法,B中注入A的方式为构造器 | 是 |
AB相互依赖(循环依赖) | B中注入A的方式为setter方法,A中注入B的方式为构造器 | 否 |
Spring在创建Bean的过程中分为三步
AOP
代理以上面AB相互依赖为例
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
getBean
方法,这个方法有两层含义
getSingleton(a)
方法,这个方法又会调用getSingleton(beanName, true)
允许提前曝光引用
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
singletonObjects
,一级缓存,存储的是所有创建好了的单例BeanearlySingletonObjects
,完成实例化,但是还未进行属性注入及初始化的对象singletonFactories
,提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象getSingleton(beanName, singletonFactory)
createBean
方法返回的Bean最终被放到了一级缓存
,也就是单例池中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);
if (singletonObject == null) {
// ....
// 省略异常处理及日志
// ....
// 在单例对象创建前先做一个标记
// 将beanName放入到singletonsCurrentlyInCreation这个集合中
// 标志着这个单例Bean正在创建
// 如果同一个单例Bean多次被创建,这里会抛出异常
beforeSingletonCreation(beanName);
boolean newSingleton = false;
// ....
// 用于记录异常相关信息
// ....
try {
// 上游传入的lambda在这里会被执行,调用createBean方法创建一个Bean后返回
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
// ...
// 省略catch异常处理
// ...
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 创建完成后将对应的beanName从singletonsCurrentlyInCreation移除
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 添加到一级缓存singletonObjects中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
creatBean
中的核心内容在完成Bean的实例化后,属性注入之前Spring将Bean包装成一个工厂对象添加进了三级缓存中
,对应源码如下:
ObjectFactory
)的getObject
方法可以得到一个bean对象getEarlyBeanReference
这个方法创建的protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
getEarlyBeanReference
AOP
的情况下,上面的代码等价于:protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
return exposedObject;
}
根据流程图串一下流程:
A依赖B,B依赖A,自然排序,所以先实例化A
AOP
相关,我们再来看一看getEarlyBeanReference
的代码:protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
开启AOP
的情况下,那么就是调用到AnnotationAwareAspectJAutoProxyCreator
的getEarlyBeanReference
方法public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 如果需要代理,返回一个代理对象,不需要代理,直接返回当前传入的这个bean对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
AOP
代理的话代理对象
而不是A的实例化阶段创建后的对象1、在给B注入的时候为什么要注入一个代理对象?
AOP
代理时2、明明初始化的时候是A对象,那么Spring是在哪里将代理对象放入到容器中的呢?
代理对象工厂
放入三级缓存populateBean()
属性填充时候去创建B代理对象
,并放入二级缓存,并删除三级缓存原始对象
3、初始化的时候是对A对象本身进行初始化,而容器中以及注入到B中的都是代理对象,这样不会有问题吗?
目标类的引用
4、三级缓存为什么要使用工厂而不是直接使用引用?换而言之,为什么需要这个三级缓存,直接通过二级缓存暴露一个引用不行吗?
延迟
对实例化阶段生成的对象
的代理
我们思考一种简单的情况,就以单独创建A为例,假设AB之间现在没有依赖关系,但是A被代理了,这个时候当A完成实例化后还是会进入下面这段代码:
// A是单例的,mbd.isSingleton()条件满足
// allowCircularReferences:这个变量代表是否允许循环依赖,默认是开启的,条件也满足
// isSingletonCurrentlyInCreation:正在在创建A,也满足
// 所以earlySingletonExposure=true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
// 还是会进入到这段代码中
if (earlySingletonExposure) {
// 还是会通过三级缓存提前暴露一个工厂对象
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
循环依赖
,那没有办法,只有给Bean先创建代理
最后一步
完成代理而不是在实例化后就立马完成代理没有循环依赖
,只是三级缓存添加了一个代理A对象工厂(不会执行),A对象会在初始化最后一步生成代理对象,然后放入一级缓存,最后清空二三级缓存
Spring是如何解决的循环依赖?
singletonObjects
),二级缓存为早期曝光对象(earlySingletonObjects
),三级缓存为早期曝光对象工厂(singletonFactories
)AOP
代理,那么通过这个工厂获取到的就是A代理后的对象
没有被AOP
代理,那么这个工厂获取到的就是A实例化的对象
对象工厂
getObject方法
来获取到对应的对象,得到这个对象后将其注入到B中为什么要使用三级缓存呢?二级缓存能解决循环依赖吗?
实例化后就要完成AOP代理
,这样违背了Spring设计的原则