循环依赖

  • java
  • 循环依赖
  • spring

什么是循环依赖

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;
}
  1. 实例化 A, 属性注入,发现需要B
  2. 容器中没有B,于是开始实例化B
  3. 对B属性注入,发现需要C
  4. 容器中没有B,于是开始实例化C
  5. 对C属性注入,发现需要A
  6. !!!但是此时,A还未完成bean的生命周期,IOC容器中查不到A,所以按照上述的逻辑执行就会出问题

如何解决循环依赖

解决循环依赖的核心就是提前暴露对象,而提前暴露的对象就是放置于第二级缓存中。下表是三级缓存的说明:

  • singletonObjects: 一级缓存,存放完整的 Bean。这里面存放的 Bean 是经历了所有生命周期的(除了销毁的生命周期),完整的,可以给用户使用的
  • earlySingletonObjects: 二级缓存,存放提前暴露的Bean,Bean 是不完整的,未完成属性注入和执行 init 方法。
  • singletonFactories: 三级缓存,存放的是对象工厂(ObjectFactory),主要是返回其持有的(未完成属性注入和执行 init 方法)对象

Bean 都已经实例化了,为什么还需要一个生产 Bean 的工厂呢?

这里实际上是跟 AOP 有关,如果项目中不需要为 Bean 进行代理,那么这个 Bean 工厂就会直接返回一开始实例化的对象,如果需要使用 AOP 进行代理,那么这个工厂就会发挥重要的作用了,这也是本文需要重点关注的问题之一。

利用三级缓存解决循环依赖

这里拿A、B互相依赖的的例子来说明:

  1. 实例化A,填充属性,A还只是个半成品
  2. 为A创建一个 Bean 工厂,并放入到 singletonFactories 中
  3. 发现A需要对象B,但是一级、二级、三级缓存均为发现对象 B
  4. 实例化B,填充属性,B还只是个半成品
  5. 为B创建一个 Bean 工厂,并放入到 singletonFactories 中
  6. 发现B需要注入 A 对象,此时在一级、二级未发现对象 A
  7. 在三级缓存中发现了对象 A,从三级缓存中得到对象 A,并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A
  8. 将对象 A 注入到对象 B 中
  9. 对象 B 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 B
  10. 对象 A 得到一级缓存中的对象 B,将对象 B 注入到对象 A 中
  11. 对象 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...