Spring如何解决循环依赖

1.背景说明

● 循环依赖是什么?

有一个Bean为AService,另一个Bean为BService

AService里面引用了属性BServiceBService里面又引用了属性AService,这样在加载Bean的时候,造成对彼此的循环依赖。

这样会导致Bean无法加载。

● 解决循环依赖的思路

说明:这里只解决单例bean的循环依赖问题。

核心思路:只需要增加一个 缓存 来存放 原始对象 即可,Spring解决此类循环依赖主要是靠三级缓存在【属性注入】阶段产生作用。

具体做法:在创建 AService 时,实例化后将 原始对象 存放到缓存中(提早暴露),然后依赖注入时发现需要 BService,便会去创建 BService,实例化后同样将 原始对象 存放到缓存中,然后依赖注入时发现需要 AService 便会从缓存中取出并注入,这样 BService 就完成了创建,随后 AService 也就能完成属性注入,最后也完成创建。这样就打破了环形调用,避免循环依赖问题。

2.三级缓存

● 一级缓存:SingletonObjects,缓存的是已经实例化、属性注入、初始化后的bean对象。

● 二级缓存:earlySingletonObjects,缓存的是实例化后,但未属性注入、初始化的Bean对象,用于提前暴露Bean

● 三级缓存:singletonFactories,缓存的是一个ObjectFactory,主要作用是生成原始对象进行AOP操作后的代理对象

3.源码分析

3.1 入口

AbstractApplicationContext.java的 这个方法进去:

// 初始化 非懒加载的单例 bean

beanFactory.preInstantiateSingletons();

        // Stop using the temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(null);

        // Allow for caching all bean definition metadata, not expecting further changes.
        beanFactory.freezeConfiguration();

        // Instantiate all remaining (non-lazy-init) singletons.
        beanFactory.preInstantiateSingletons();

进入到 DefaultListableBeanFactory的preInstantiateSingletons方法

        // Trigger initialization of all non-lazy singleton beans...
        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) {
                        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);
                }
            }
        }

3.2 getBean方法

DefaultListableBeanFactory中,进入getBean

这里获取的是这种类型的bean:

(1)非抽象的BeanDefinition

(2)单例的BeanDefinition

(3)非懒加载的BeanDefinition

else {
    getBean(beanName);
}

3.3 doGetBean方法

实际干活的是 AbstractBeanFactory中的 doGetBean

    protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException

如果不存在已有的单例对象,且beanDefination是单例,那么进入 createBean方法

                if (mbd.isSingleton()) {
                    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);
                }

3.4 createBean方法

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

createBean方法 返回一个Object类型

核心逻辑:

try {
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isTraceEnabled()) {
        logger.trace("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}

3.5 doCreateBean方法

3.5.1 实例化对象

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

● 首先,实例化一个对象:

instanceWrapper = createBeanInstance(beanName, mbd, args)

3.5.2 加入三级缓存

接着,把创建对象的lambda表达式放到三级缓存。

这里是为了避免后期的循环依赖,所以在bean初始化完成前将创建实例的ObjectFactory加入工厂。

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
 isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
   if (logger.isTraceEnabled()) {
   logger.trace("Eagerly caching bean '" + beanName +
   "' to allow for resolving potential circular references");
}
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

说明:

(1)getEarlyBeanReference(beanName, mbd, bean) 方法 会返回遍历工厂内的所有后置处理器,去处理原始的bean,并返回最终经过层层包装后的 代理对象

(2)这里并不会马上执行getEarlyBeanReference方法,有循环依赖的时候才执行。

3.5.3 属性赋值

场景:AService 中要注入属性BService

进入populateBean方法

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 

核心方法:

if (pvs != null) {
 applyPropertyValues(beanName, mbd, bw, pvs);
}

applyPropertyValues中的核心方法:

Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

点进去:

if (value instanceof RuntimeBeanReference) {
   RuntimeBeanReference ref = (RuntimeBeanReference) value;
   return resolveReference(argName, ref);
}

核心方法:resolveReference(argName, ref),点进去:

else {
    String resolvedName;
    if (beanType != null) {
      NamedBeanHolder<?> namedBean = 
      this.beanFactory.resolveNamedBean(beanType);
      bean = namedBean.getBeanInstance();
      resolvedName = namedBean.getBeanName();
     } else {
        resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
        bean = this.beanFactory.getBean(resolvedName);
     }
     this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}

注意:这里开始无限套娃之旅,即:

(1)这里有一句:bean = this.beanFactory.getBean(resolvedName),在该场景下,作用是获取属性Bservice

(2)然后 B在创建过程中,最终又会执行这句bean = this.beanFactory.getBean(resolvedName),去获取属性Aservice

3.6 循环依赖的闭环

● 闭环形成的关键点

当 Aservice --> Bservice --> Aservice 这个过程,进行到第二次 获取 Aservice 的时候,会通过 getSingleton 方法

获取Aservice,即:

可以看到在第三级缓存中调用了 singletonFactories.get(beanName)

按照上文所说,会触发执行有 AOP 操作,返回代理对象。如果没有AOP操作的话,返回原始对象。

此外,还会把Aservice上移到二级缓存中、并删除三级缓存的数据。

● Bservice创建完成

如此一来,容器在创建Bservice的时候,就可以拿到 Aservice,完成BService的创建,并将Bservice加入一级缓存。

● Aservice创建完成

当Bservice创建完成后,就可以在Aservice中完成属性Bservice的注入,从而完成AService的创建,将Aservice加入一级缓存。

4.总结

梳理整个过程如下:

● 首先会获取 AService 对应的 Bean 对象。

先是调用 doGetBean() 中的第一个 getSingleton(beanName) 判断是否有该 Bean 的实例,有就直接返回了。(显然这里没有)

然后调用 doGetBean() 中的第二个 getSingleton() 方法来执行 doCreateBean() 方法。

先进行实例化操作(也就是利用构造函数实例化),此时实例化后生成的是原始对象。

将原始对象通过 lambda表达式 进行封装成 ObjectFactory 对象,通过 addSingletonFactory 加入三级缓存中。

然后再进行属性注入,此时发现需要注入 BService 的 Bean,会通过 doGetBean() 去获取 BService 对应的 Bean。

● 获取BService 对应的 Bean。

同样调用 doGetBean() 中的第一个 getSingleton(beanName) 判断是否有该 Bean 的实例,显然这里也是不会有 BService 的 Bean 的。

然后只能调用 doGetBean() 中的第二个 getSingleton() 方法来执行 doCreateBean() 方法来创建一个 BService 的 Bean。

同样地先进行实例化操作,生成原始对象后封装成 ObjectFactory 对象放入三级缓存中。

然后进行属性注入,此时发现需要注入 AService 的 Bean。

● 第二次获取AService 对应的 Bean

此时调用调用 doGetBean() 中的第一个 getSingleton(beanName) 查找是否有 AService 的 Bean。此时会触发三级缓存,也就是调用 singletonFactories.get(beanName)

因为三级缓存中有 AService 的原始对象封装的 ObjectFactory 对象,所以可以获取到的代理对象或原始对象,并且上移到二级缓存中,提前暴露给 BService 调用。

所以 BService 可以完成属性注入,然后进行初始化后,将 Bean 放入一级缓存,这样 AService 也可以完成创建。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容