spring的循环依赖怎么解决?

Spring通过三级缓存的方式来解决循环依赖问题。三级缓存分别是:

  1. singletonObjects:一级缓存,用于保存实例化、注入、初始化完成的bean实例。
  2. earlySingletonObjects:二级缓存,用于保存实例化完成的bean实例。
  3. singletonFactories:三级缓存,用于保存bean创建工厂,以便于后面扩展。

下面是Spring解决循环依赖的步骤:

  1. 创建Bean A,首先去一级缓存中获取,如果没有则去二级缓存中获取,如果还是没有则去三级缓存中获取。如果都没有则开始创建Bean A。

  2. 实例化Bean A,将其放入到二级缓存中。注意此时Bean A已经实例化完成,但是还没有進行属性注入和初始化。

  3. 对Bean A进行属性注入时,发现依赖了Bean B,此时递归去创建Bean B。

  4. 创建Bean B的过程与上述类似,实例化完成后将其放入到二级缓存中。

  5. 对Bean B进行属性注入时,发现依赖了Bean A,此时递归去创建Bean A。

  6. 从二级缓存中获取到已经实例化完成的Bean A,并把它放到一级缓存中。返回Bean A的实例,继续对Bean B进行属性注入。

  7. Bean B完成属性注入和初始化后,将其放入到一级缓存中,并从二级缓存和三级缓存中移除。返回Bean B的实例,继续对Bean A进行属性注入。

  8. Bean A完成属性注入和初始化后,将其放入到一级缓存中,并从二级缓存和三级缓存中移除。至此,循环依赖问题解决。

关键点在于:

  1. 实例化Bean时就把它放入到缓存中,而不是等到完全初始化好再放入缓存。
  2. 每个Bean在创建过程中,都会先去缓存中查找是否已经存在,如果已经存在说明发生了循环引用,直接使用缓存中的实例而不是再去创建。
  3. 三级缓存的作用在于提前暴露实例的引用,如果没有三级缓存,按照上面的流程,会导致Bean B在注入Bean A时又去创建Bean A,无法终止循环。

这就是Spring解决循环依赖的核心思路。通过三级缓存提前暴露实例,并在递归时检查缓存而不是重复创建实例,从而解决了循环依赖的问题。

举例说明:
以下代码基于Spring 5.2.8版本的AbstractAutowireCapableBeanFactory类:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
    
    /** Cache of singleton objects: bean name to bean instance. */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of early singleton objects: bean name to bean instance. */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    /** Cache of singleton factories: bean name to ObjectFactory. */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            // 1. 实例化Bean
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            // 2. 将实例化后的Bean放入到三级缓存中
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 3. 对Bean进行属性注入
            populateBean(beanName, mbd, instanceWrapper);
            // 4. 对Bean进行初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }

        if (earlySingletonExposure) {
            // 5. 从三级缓存中获取Bean
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }

        return exposedObject;
    }

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 1. 先从一级缓存中获取Bean
        Object singletonObject = this.singletonObjects.get(beanName);
        // 如果一级缓存中没有,并且当前Bean正在创建中
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // 2. 从二级缓存中获取Bean
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    // 3. 从三级缓存中获取Bean
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                // 将Bean工厂放入到三级缓存中
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
            }
        }
    }
}

主要步骤:

  1. doCreateBean方法中,首先实例化Bean。
  2. 如果允许循环引用,则将实例化后的Bean包装成ObjectFactory放入到三级缓存singletonFactories中。
  3. 对Bean进行属性注入,如果发现依赖了其他Bean,则递归去创建其他Bean。
  4. 对Bean进行初始化。
  5. 如果允许循环引用,则尝试从三级缓存singletonFactories中获取Bean。因为在第2步中已经将Bean放入到三级缓存中了,所以这里可以获取到。

getSingleton方法中:

  1. 先从一级缓存singletonObjects中获取Bean,如果存在则直接返回。
  2. 如果一级缓存中不存在,且当前Bean正在创建中,则从二级缓存earlySingletonObjects中获取Bean,如果存在则直接返回。
  3. 如果二级缓存中也不存在,则从三级缓存singletonFactories中获取Bean工厂,如果存在则调用工厂方法创建Bean,并将Bean放入到二级缓存中,并从三级缓存中移除。

通过以上步骤,Spring就可以解决循环依赖问题。关键在于提前将实例化后的Bean放入到缓存中,并在递归时从缓存中获取Bean而不是重复创建。三级缓存的作用在于提前暴露Bean的引用,打破循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值