一、什么是循环依赖
注入的三种方式:
-
setter 方法进行注入
-
构造方法进行赋值,但是这种情况不能实现循环依赖
-
field ( 反射,例如:@Autowired)
Spring 如何解决循环依赖:三级缓存
/** Cache of singleton objects: bean name to bean instance. */
// 用于存放完全初始化好的 bean 从该缓存中取出的 bean 可以直接使用 (单例Bean)
一级缓存: private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of early singleton objects: bean name to bean instance. */
// 存放原始的 bean 对象用于解决循环依赖,注意: 存到里面的对象还没有被填充属性,(半成品的 bean)
二级缓存: private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Cache of singleton factories: bean name to ObjectFactory. */
// 存放 bean 工厂对象解决循环依赖
三级缓存: private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
循环依赖怎么解决 ( 看源码 )
1、首先进入 refresh() 方法,找到 其中的 finishBeanFactoryInitialization() 方法,并进入其中
// Instantiate all remaining (non-lazy-init) singletons.
// 创建所有剩余的非懒加载的单例类
// 剩余的单例对象: Spring 自己提供的(BeanPostProcessors),还有我们自己提供的(dao 层,service 层)
finishBeanFactoryInitialization(beanFactory);
2、找到 preInstantiateSingletons() 方法
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化单例对象之前要做的
beanFactory.preInstantiateSingletons();
// 在该方法中,会循环遍历所有的 beanName,里边会有三个熟悉的类,一个是Config, X, Y,执行顺序按顺序执行
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
在 for 循环中,会有一些判断
// bd 不是抽象的 且 这个 bd 是单例的 且 这个 bd 不是懒加载的 这个 if 判断才生效
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果是 FactoryBean,进入 if 判断,否则进入下边的 else
if (isFactoryBean(beanName)) {
// 如果是 FactoryBean 则加上 &
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 因为不是 FactoryBean,所以直接进入 getBean() 方法
// 需要创建 X 对象,所以要判断工厂是否有该对象
getBean(beanName);
}
}
进入 getBean() 方法
@Override
public Object getBean(String name) throws BeansException {
// 空壳方法
return doGetBean(name, null, null, false);
}
进入空壳方法 doGetBean() 方法
// 找到改行代码
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
// 表示获取单例对象,但是到目前为止工厂中并没有该对象,所以此时 sharedInstance 为 null
// 进入这个方法
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
// 调用 getSingleton() 方法
Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存 singletonObjects
Object singletonObject = this.singletonObjects.get(beanName);
// 第一次 isSingletonCurrentlyInCreation(beanName): 不成立,因为没有往里边的 set 集合存放内容
// 第二次 isSingletonCurrentlyInCreation(beanName): 成立
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 二级缓存 earlySingletonObjects
singletonObject = this.earlySingletonObjects.get(beanName);
// allowEarlyReference: 是否允许存放
if (singletonObject == null && allowEarlyReference) {
// 三级缓存 singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
// 这里就开始涉及到三级缓存了
// 三个对象最主要的区别: 泛型不同,三级缓存存放的是 ObjectFactory 对象
// 执行完
Object sharedInstance = getSingleton(beanName);
// 获取到的 sharedInstance 的值为 null
// 那么接下来就会开始创建这个对象,一直到如下代码
if (!typeCheckOnly) {
// 添加到 alreadyCreated set 集合中,表示已经创建过一次,防止重复创建
markBeanAsCreated(beanName);
}
// 此时这个对象已经创建好了,仅仅只是个对象,因为里边的属性还没有填充好
// 继续往下走,直到遇到如下的注释
// Create bean instance.创建 bean 实例
// 这里要注意一下,这里的 getSingleton() 和刚才遇到的 getSingleton() 两个是不一样的
if (mbd.isSingleton()) {
// 进入这个方法 createBean()
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.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
进入 getSingleton() 方法
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) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName, "...");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 创建单例之前的回调
// 这里将X对象标记为正在创建中,存放到 singletonsCurrentlyInCreation 集合中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 三级缓存
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
// 这里有个问题: 一级缓存取不到,就去三级缓存中去取???而且三级缓存调用了一个方法 getObject()???
// 可以知道三级缓存的 value 值是 ObjectFactory 对象,这个对象中会有一个方法就是 getObject()
// 函数式接口,比如还有 Runnable 也实现了这个注解
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
// 也就是说,这里调用 getObject() 方法的是 getSingleton() 方法的Lamda表达式
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.
destroySingleton(beanName);
throw ex;
}
});
// 在调用 getObject() 方法的时,其实是执行的是,如下的代码
return createBean(beanName, mbd, args);
进入 createBean() 方法
// 找到如下的代码,这里调用 doCreateBean(),用来创建 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
// 进入 doCreateBean() 方法,看到如下的代码
if (instanceWrapper == null) {
// 创建当前 bean 的实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 所以当 createBeanInstance() 这个方法执行完后,这个对象已经创建好了
// 继续向下执行
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 进入 addSingletonFactory() 方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 判断一级缓存中是否包含 beanName,此时不包含,取反为 true,进入 if
if (!this.singletonObjects.containsKey(beanName)) {
// 将 beanName 以及 singletonFactory(匿名内部类) 存放到三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 二级缓存中什么也没有,移不移除无所谓
this.earlySingletonObjects.remove(beanName);
// 所有被创建的对象都会被放进去(只存 beanName)
this.registeredSingletons.add(beanName);
}
}
}
// 执行完返回继续执行,直到如下的代码
// 设置属性,非常重要
populateBean(beanName, mbd, instanceWrapper);
// 当执行完该方法后发现,X对象的属性Y已经被填充
// 细节可以进入该方法,找到如下代码
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 进入 postProcessProperties() 方法,找到如下代码
metadata.inject(bean, beanName, pvs);
// 进入 inject() 方法,找到如下代码
element.inject(target, beanName, pvs);
// 进入 inject() 方法,找到如下代码
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
// 进入 resolveDependency() 方法,找到如下代码
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
// 进入 doResolveDependency() 方法,找到如下代码
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
// 进入 resolveCandidate() 方法,找到如下代码
return beanFactory.getBean(beanName);
// 进入 getBean() 方法,步骤与 x 一样
// 进入 doGetBean() 方法
// 进入 getSingleton() 方法,因为要调用两次该方法,第一次调用和 x 一样
// 再次进入 getSingleton() 方法
// 在进入该方法的匿名内部类,也就是如下代码
return createBean(beanName, mbd, args);
// 进入 createBean() 方法,找到如下代码
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
// 进入 doCreateBean() 方法,找到如下代码
instanceWrapper = createBeanInstance(beanName, mbd, args);
// 此时对象 Y 的 bean 实例已经被创建
// 继续往下执行
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 上一次执行该方法,是将 x 放到三级缓存
// 此时也一样,将 y 放到三级缓存
此时三个缓存状态如下图所示:
需要注意的是,三级缓存中存放了 X 和 Y 的匿名内部类,但是还没有执行
// 继续执行代码,该为 y 进行属性填充
populateBean(beanName, mbd, instanceWrapper);
// 进入该方法,找到如下代码
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 或
applyPropertyValues() 方法(beanName, mbd, bw, pvs);
// 这两个有点区别: 当我们使用 @AUtowried 注解时,走 postProcessProperties() 方法,使用 xml 配置类时,使用 applyPropertyValues() 方法
// 由于我使用的是 @Autowired 注解,那么走上边那行代码
// 进入 postProcessProperties() 方法,我们需要对属性进行注入
metadata.inject(bean, beanName, pvs);
// 进入该方法
// 该方法使用循环的方式获取 X 中的属性,一次再调用 inject() 方法
element.inject(target, beanName, pvs);
// 该方法通过反射的方式获取到X中的属性
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
// 该 resolveDependency() 方法中文为解决依赖,我们可以看到其中的两个参数,一个是desc另一个是beanName,此时分别为: y, x
// 进入奥该方法中,找到如下代码
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
// 进入奥该方法中,找到如下代码
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
// 代码如下
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException {
return beanFactory.getBean(beanName);
}
// 中文翻译是解决候选者,就是解决X对象中的属性,这个属性没有,那么就创建一个
// 继续执行,一直到 getBean() 方法,但要注意此时 name 为 x,不是 y
// 进入 doGetBean() 方法,找到如下代码
Object sharedInstance = getSingleton(beanName);
// 进入该方法
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存中找不到
Object singletonObject = this.singletonObjects.get(beanName);
// 这次这里成立,singletonObject 为空且X处于正在创建中,因此进入该 if 判断
// return this.singletonsCurrentlyInCreation.contains(beanName);
// singletonsCurrentlyInCreation 集合当中有 X 和 Y
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 由于二级缓存中没有值,所以为 null
singletonObject = this.earlySingletonObjects.get(beanName);
// 二级缓存中没有值,且 allowEarlyReference 为 true 固定值
if (singletonObject == null && allowEarlyReference) {
// 调用三级缓存中的匿名内部类
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 执行Lamda表达式
singletonObject = singletonFactory.getObject();
// 存放到二级缓存中,暴露一个工厂(也可以说是半成品)
this.earlySingletonObjects.put(beanName, singletonObject);
// 删除三级缓存中对应的值
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
// 继续执行一直到如下代码所示,执行第二个 getSingleton() 方法
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
// 当该方法的 beforeSingletonCreation() 方法执行完后,说明:
beforeSingletonCreation(beanName);
// ***********************************************************
// *** 此时 X 和 Y 的状态是实例化完成,但还没有初始化,表示正在创建中 ***
// ***********************************************************
// singletonsCurrentlyInCreation 集合中存在 x 和 y
// 继续执行执行到如下所示时,进入 getObject() 方法
singletonObject = singletonFactory.getObject();
// 其实是调用了下行代码的 getEarlyBeanReference() 方法
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 进入该方法
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;
}
// 注意: 这里要注意,什么时候才会需要进入 if 判断
// 上边的代码中,if 判断的部分是一个后置处理器,相当于说这部分是程序员可以对代码进行扩展的地方,如果不扩展,那么可以注释掉,Spring 自己也会对他做一个扩展
此时三个缓存状态如下图所示:
// 当执行完饭回到如下代码时
Object sharedInstance = getSingleton(beanName);
// 此时 sharedInstance 是有值的,X对象第一次调用该方法时,sharedInstance 为 null
// 因此如下的 if 条件是满足的,进入 if
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 + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 继续往下执行,直到如下代码
return (T) bean;
// 将获取到的x对象返回,此时x完成实例化但还没有初始化完成
// 一路返回到 Y 对象所对应的 doGetBean() 中的第二个 getSingleton() 方法
addSingleton(beanName, singletonObject);
// 进入 addSingleton() 方法,将Y对象放到一级缓存中,此时Y即完成实例化也完成初始化
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 将Y对象添加到一级缓存
this.singletonObjects.put(beanName, singletonObject);
// 删除三级缓存中的Y对象
this.singletonFactories.remove(beanName);
// 删除二级缓存中的Y对象
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
// 执行完后返回到 doGetBean() 方法
// 此时Y对象创建完成,X对象还没有创建完成
此时三个缓存状态如下图所示:
// 继续执行代码,一路返回到 X 对象所对应的 doGetBean() 中的第二个 getSingleton() 方法
addSingleton(beanName, singletonObject);
// 将 X 对象添加到一级缓存中
此时三个缓存状态如下图所示:
// 此时 X 和 Y 都完成了实例化和初始化,并且放在了一级缓存中
// X 对象就创建成功了,一路返回到最开始的那个循环,此时该循环 Y
// 执行 getBean() 方法,在执行 doGetBean() 方法
// 在执行到 doGetBean() 方法中的 getSingleton() 方法中
// 现在一级缓存中去找,但是此时一级缓存中已经有 Y 对象了,所以不再需要取寻找,直接返回即可
问题:
1、为什么构造方法注入属性不能解决循环依赖?
// 答: Spring 解决循环依赖依靠的是 Bean 的 "中间态" 这个概念,而这个中间态指的是已经实例化,但还没完成初始化的状态。而构造器是需要完成实例化对象,所以构造器无法解决循环依赖
2、使用二级缓存能不能解决循环依赖?
// 答: 是可以的,三级缓存中存放的是 ObjectFactory 对象,为什么要存放这个对象,循环依赖中,这个对象存储的是一个 Lamda 表达式,这个表达式调用了 getEarlyBeanReference() 方法,这个方法中我们可以看到如果不执行 if 判断,那么传进来什么值,就返回什么值,问题就在于这个 if 做了什么,SmartInstantiationAwareBeanPostProcessor 是一个后置处理器,这个处理器用来创建代理类对象,假如我们生成一个代理类 AOP,比如 X 实现了 AOP,那么注入到其他 bean 的时候,得到的对象不是最终的代理对象,而是原始对象(通过上下文我们可以得到这个 bean 此时的状态还在实例化过程中)。就是说下面的代码的返回值表示三级缓存中的 value,如果只有二级缓存,那么只能获得原始对象,而不是代理对象
// 说简单点就是三级缓存中存放的 value 值是 ObjectFactory 对象,这个对象可能是普通的实例对象,也可能是普通实例对象的代理对象,如果不涉及到 AOP,那么使用二级缓存那么程序可以执行,不涉及到 AOP 那么不会走下面代码的 if 判断,但是如果涉及到 AOP,那么就需要的是代理对象,所以二级缓存是不可以的
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() 方法
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
// 进入 wrapIfNecessary() 方法,找到如下代码
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
// 将我们给定的对象生成一个代理
// 此时 exposedObject 将变成生成的代理,而不是原先的原始对象
有兴趣的同学可以关注我的个人公众号,期待我们共同进步!!!