侧边栏壁纸
博主头像
惊羽博主等级

hi ,我是惊羽,前生物学逃兵,现系统工程沉迷者 . 贝壳签约工程师 , 曾被雇佣为 联拓数科 · 支付研发工程师 、京东 · 京东数科 · 研发工程师、中国移动 · 雄安产业研究院 · 业务中台技术负责人 .

  • 累计撰写 100 篇文章
  • 累计创建 14 个标签
  • 累计收到 9 条评论

spring(5) - Bean实例化中,对循环依赖的处理

惊羽
2021-06-21 / 0 评论 / 0 点赞 / 128 阅读 / 4,632 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-06-21,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1. 背景知识

(1) spring(3) - springboot启动过程
(2) spring(4) - spring Bean创建并注册到容器

2. Bean创建

通过 背景知识,我们知道,spring在创建Bean的时候,分三步,先创建bean,然后注册到容器中,之后进行属性装配,在进行初始化

2.1 AbstractAutowireCapableBeanFactory 类的 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
        // ① 创建实例wapper
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }
                mbd.postProcessed = true;
            }
        }

        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
            // ③ 将该实例放到容器缓存中
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

        Object exposedObject = bean;

        try {
         // ④ 为实例wapper装配属性
            this.populateBean(beanName, mbd, instanceWrapper);
            // ⑤ 为实例wapper进行初始化
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }
        
         ......
    }

2.2 进入 // ③ 将该实例放到容器缓存中this.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);
                this.registeredSingletons.add(beanName);
            }

        }
    }

我们看到,此处逻辑为 将该实例放到了 singletonFactories 属性中,并将 singletonFactories 属性中的引用移出掉了,这两个属性是什么意思呢?
点击其中一个属性,我们看下属性的声明 ,发现这几个属性都属于父类 DefaultSingletonBeanRegistry ,那就明白啦 , 这个类就是处理spring Bean 容器处理缓存的类,如下 :

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // 第一级缓存
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    // 第三级缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    // 第二级缓存
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);
   ....
}
一级缓存singletonObjects是完整的bean,它可以被外界任意使用,并且不会有歧义。
二级缓存earlySingletonObjects是不完整的bean,没有完成初始化,它与singletonObjects的分离主要是职责的分离以及边界划分;
三级缓存singletonFactories,其职责就是包装一个bean,有回调逻辑,所以它的作用非常清晰,并且只能处于第三层。

3 应用三层缓存对循环依赖的处理举例

如果 A,B 两个类互相依赖,且需要实例化,当只有一层缓存 singletonObjects 的时候,A 实例化调用B,B实例化调用A,就无法结束了;
此时加一层缓存 earlySingletonObjects ,用于存储还未完成初始化的实例,但是已经完成了创建,在创建A的时候,发现需要创建B,就去创建B,找B的时候一次从 第一级缓存,二级缓存,三级缓存中找, 最后在三级缓存singletonFactories中找到其工厂,直接创建B 的未初始化实例放到二级缓存中,并将三级缓存中的B工厂清除,然后返回继续实例化A,因为从二级缓存中找到了B的未初始化引用,得以继续完成实例化A,当需要继续初始化B时,再将A的完整实例引用从一级缓存给到B实例,这样就完成了循环依赖的实例化;
根本原理是 从JVM层面,将实例化分成了 声明, 初始化 两个阶段,(也就是分层的思想),在一层无法解决的时候,通过引入分层解决问题;

0
广告 广告

评论区