循环依赖
什么是循环依赖
a->b->c->a
- A 依赖于 B
- B 依赖于 C
- C 依赖于 A
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private C c;
}
@Component
public class C {
@Autowired
private A a;
}
- 实例化 A, 属性注入,发现需要B
- 容器中没有B,于是开始实例化B
- 对B属性注入,发现需要C
- 容器中没有B,于是开始实例化C
- 对C属性注入,发现需要A
- !!!但是此时,A还未完成bean的生命周期,IOC容器中查不到A,所以按照上述的逻辑执行就会出问题
如何解决循环依赖
解决循环依赖的核心就是提前暴露对象,而提前暴露的对象就是放置于第二级缓存中。下表是三级缓存的说明:
- singletonObjects: 一级缓存,存放完整的 Bean。这里面存放的 Bean 是经历了所有生命周期的(除了销毁的生命周期),完整的,可以给用户使用的
- earlySingletonObjects: 二级缓存,存放提前暴露的Bean,Bean 是不完整的,未完成属性注入和执行 init 方法。
- singletonFactories: 三级缓存,存放的是对象工厂(ObjectFactory),主要是返回其持有的(未完成属性注入和执行 init 方法)对象
Bean 都已经实例化了,为什么还需要一个生产 Bean 的工厂呢?
这里实际上是跟 AOP 有关,如果项目中不需要为 Bean 进行代理,那么这个 Bean 工厂就会直接返回一开始实例化的对象,如果需要使用 AOP 进行代理,那么这个工厂就会发挥重要的作用了,这也是本文需要重点关注的问题之一。
利用三级缓存解决循环依赖
这里拿A、B互相依赖的的例子来说明:
- 实例化A,填充属性,A还只是个半成品
- 为A创建一个 Bean 工厂,并放入到 singletonFactories 中
- 发现A需要对象B,但是一级、二级、三级缓存均为发现对象 B
- 实例化B,填充属性,B还只是个半成品
- 为B创建一个 Bean 工厂,并放入到 singletonFactories 中
- 发现B需要注入 A 对象,此时在一级、二级未发现对象 A
- 在三级缓存中发现了对象 A,从三级缓存中得到对象 A,并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A
- 将对象 A 注入到对象 B 中
- 对象 B 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 B
- 对象 A 得到一级缓存中的对象 B,将对象 B 注入到对象 A 中
- 对象 A 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 A
doCreateBean
protected Object doCreateBean(
final String beanName,
final RootBeanDefinition mbd,
Object[] args
) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
// 1.实例化对象
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;
Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null;
// 2.判断是否单例 且 允许循环引用(默认 true),且正在在创建
// singletonsCurrentlyInCreation这样一个缓存防止了bean对象在循环引用的过程中重复创建的问题。
boolean earlySingletonExposure = (mbd.isSingleton()
&& this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 添加到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 3.填充属性
this.populateBean(beanName, mbd, instanceWrapper);
// 4.执行初始化方法,并创建代理
exposedObject = initializeBean(beanName, exposedObject, mbd);
// ....省略, 一会讲
return exposedObject;
}
addSingletonFactory
添加三级缓存的方法如下:
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);
// 注册单例beanName
this.registeredSingletons.add(beanName);
}
}
}
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
getEarlyBeanReference
Spring 一开始提前暴露的并不是实例化的 Bean,而是将 Bean 包装起来的 ObjectFactory
为什么要这么做呢?
这实际上涉及到 AOP,如果创建的 Bean 是有代理的,那么注入的应该是代理 Bean,而不是原始的 Bean。但是 Spring 一开始并不知道 Bean 是否会有循环依赖
- 在没有循环依赖的情况下,Spring 都会在完成填充属性,并且执行完初始化方法之后再为其创建代理。
- 在循环依赖的情况下,Spring 就不得不为其提前创建代理对象。因此,这里就涉及到应该在哪里提前创建代理对象
Spring 的做法就是在 ObjectFactory 中去提前创建代理对象。它会执行 getObject() 方法来获取到 Bean
() -> getEarlyBeanReference(beanName, mbd, bean)
protected Object getEarlyBeanReference(
String beanName,
RootBeanDefinition mbd,
Object bean
) {
Object exposedObject = bean;
// 判读我们容器中是否有InstantiationAwareBeanPostProcessors类型的后置处理器
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 获取所有BeanPostProcessor
for (var bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
var ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// 如果需要代理,这里会返回代理对象;否则返回原始对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 记录已被代理的对象
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
wrapIfNecessary
创建代理对象
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//已经被处理过(解析切面时targetSourcedBeans出现过) 就是自己实现创建动态代理逻辑
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
//不需要增强的
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//是不是基础的bean 是不是需要跳过的 重复判断 ( 因为循环依赖是可以改变bean的,如果把bean改成了advisor呢)
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 根据当前bean找到匹配的advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 当前bean匹配到了advisor
if (specificInterceptors != DO_NOT_PROXY) {
// 标记为已处理
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建我们的真正的代理对象
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;
}
populateBean
填充属性的
protected void populateBean(
String beanName,
RootBeanDefinition mbd,
@Nullable BeanWrapper bw
) {
// ... 省略
// 给 InstantiationAwareBeanPostProcessors 最后一次机会在属性注入前修改Bean的属性值
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 选择注入模式
// 默认是0, 不会走下面分支的逻辑
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根据name注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根据class类型注入
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否进行依赖检查,默认为 false
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// 在这里会对 @Autowired 标记的属性进行依赖注入
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
postProcessProperties到getBean中间还会有好几个方法,Spring我劝你善良
addSingleton
从三级缓存中objectFactory创建得到的、初始化完成的对象,通过调用addSingleton放到一级缓存中
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
Loading...