3.4 spring5源码系列--循环依赖的设计思想 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖3.2spring源码系列----循环依赖源码分析3.3 Spring5源码---循环依赖过程中spring读取不完整bean的最终

前端之家收集整理的这篇文章主要介绍了3.4 spring5源码系列--循环依赖的设计思想 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖3.2spring源码系列----循环依赖源码分析3.3 Spring5源码---循环依赖过程中spring读取不完整bean的最终前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

前面已经写了关于三篇循环依赖的文章,这是一个总结篇

第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖

第二篇: 3.2spring源码系列----循环依赖源码分析

第三篇: 3.3 Spring5源码---循环依赖过程中spring读取不完整bean的最终

现在总结循环依赖的思想

学了那么多,为什么说见多才能识广呢,知道别人是如何解决某一类问题的,也就是优秀代码的魅力. 这也是为什么要学习别人的代码的原因.

思想才是我们可以在工作中借鉴使用的

1. 循环依赖的三级缓存设计

2. 接口函数

 


 

一. 循环依赖的三级缓存设计

再循环依赖的过程中设计了三级缓存,他们的作用分别是

1. 一级缓存: 用来存放完整的bean

2. 二级缓存: 用来存放早期的,纯净的bean

3. 三级缓存: 用来存放接口函数.

   /** Cache of singleton objects: bean name to bean instance. */
    /**
     * 一级缓存  这个就是我们大名鼎鼎的缓存池,用于保存我们所有的实例bean
     private final Map<String,Object> singletonObjects = new ConcurrentHashMap<>(256);

    * Cache of singleton factories: bean name to ObjectFactory. *
     * 三级缓存  该map用户缓存key为beanName,value为objectFactory(包装为早期对象)
     singletonFactories = new HashMap<>(16* Cache of early singleton objects: bean name to bean instance. *
     * 二级缓存,用户缓存我们的key为beanName,value是我们的早期对象(此时对象属性还没有...)
     earlySingletonObjects = 16);

 

细细想来,这三个缓存都非常有存在的必要.

1.1 引入一级缓存

刚开始,只有一级缓存,在整个bean创建完成以后,将其完整的bean放入到一级缓存中. 这样有什么问题? 

1. bean创建一共有三大步骤,(实例化,属性赋值,初始化) 等到整个过程都创建完,在存入一级缓存,多线程怎么办? 第一个线程创建bean的过程中,又来了一个线程,他发现一级缓存这时候还没有,就回去再次创建. 那不就重复了么? ioc要求,bean是单例的.

2. 加锁,加锁能否解决这个问题? 能,但是效率超级低. 对一级缓存加锁,那么所有的对象创建过程中都要等待. 哪怕人家已经创建成功过. 效率太低,不能接受

3. 于是就引入了二级缓存. 

1.2 引入二级缓存

二级缓存的引入,可以解决一级缓存创建bean链路过长的问题,他在bean一旦被创建,立刻就放入到二级缓存. 整个bean创建完成以后,在放入到一级缓存,删除二级缓存. 这样做可以解决多线程创建bean的问题. 缩短了整个链路. 同时,每次从缓存中先获取bean,如果一级缓存中已经有了,那么直接返回. 不用在执行后面的创建代码

那么,二级缓存有什么问题呢?

这就还需要知道一个问题,那就是动态代理创建bean. 什么时候,去使用动态代理创建bean? 通常我们说在初始化之后,调用bean的后置处理器创建bean. 这只是大多数bean创建动态代理的时候. 那如果有循环依赖呢? 有循环依赖,还在初始化之后创建就晚了. 这是需要在实例化之后创建. 这样,动态代理的代码就和创建bean耦合在一块了. 违背单一性原则.

于是,引入了三级缓存

1.3 引入三级缓存

三级缓存的引入是为了解决耦合问题. 让每一个方法只做一件事. 巧妙的使用了接口函数

 这个接口函数什么用呢? 就相当于js中的回调函数. 我在前面定义好,但是不执行. 直到满足条件了,才执行. 这个方法,可以大范围应用到实践工作中.

比如: 调用动态代理创建bean. 刚开始实例化完成以后,我就赋予你这个能力,你可以调用动态代理. 但是,到后面,你是否真的能够运用这个能力呢? 不一定,只有满足条件,才会运用这个能力. 

二. 定义接口函数,也叫钩子函数

在循环依赖源码中,两次使用到接口函数的方式. 

第一个是创建bean的时候. 第二个是三级缓存

下面来看看源码,

第一次: 创建bean的时候,定义了一个钩子函数createBean()

sharedInstance = getSingleton(beanName,() -> {
    try {
        // 这里定义了一个钩子函数. 此时只是定义,并不执行. 在真正需要创建bean的地方才会执行
        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;
    }
});

实际上调用的时机是: 在getSingleton方法里面. 回调接口函数.

public Object getSingleton(String beanName,ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName,"Bean name must not be null");
        synchronized (this.singletonObjects) {
             第一步: 从一级缓存中获取单例对象
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                if (.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName,1)">Singleton bean creation not allowed while singletons of this factory are in destruction " +
                            (Do not request a bean from a beanfactory in a destroy method implementation!));
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(Creating shared instance of singleton bean '" + beanName + ' 第二步: 将bean添加到singletonsCurrentlyInCreation中,表示bean正在创建
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == );
                 (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                 {
                    // 第三步: 这里调用getObject()钩子方法,就会回调匿名函数,调用singletonFactory的createBean()
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                 (IllegalStateException ex) {
                     Has the singleton object implicitly appeared in the meantime ->
                     if yes,proceed with it since the exception indicates that state.
                    singletonObject = (beanName);
                    ) {
                        throw ex;
                    }
                }
                 (BeanCreationException ex) {
                     (recordSuppressedExceptions) {
                        for (Exception suppressedException : .suppressedExceptions) {
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                     ex;
                }
                finally {
                    ;
                    }
                    afterSingletonCreation(beanName);
                }
                 (newSingleton) {
                    addSingleton(beanName,singletonObject);
                }
            }
             singletonObject;
        }
    }

 

第二次调用: 是在三级缓存定义的时候

调用addSingletonFactory(...)定义了一个钩子函数. 这里仅仅是定义,并不执行

 把我们的早期对象包装成一个singletonFactory对象,该对象提供了getObject()方法,把静态的bean放到三级缓存中去了.
addSingletonFactory(beanName,() -> getEarlyBeanReference(beanName,bean));

然后进入到addSingletonFactory内部,只是把singletonFactory放入到了三级缓存中,这里只是定义,也并没有执行

protected void addSingletonFactory(String beanName,ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory,1)">Singleton factory must not be nullif (!.singletonObjects.containsKey(beanName)) {
                 加入到三级缓存中,暴露早期对象用于解决循环依赖.
                this.singletonFactories.put(beanName,singletonFactory);

                 从二级缓存中删除
                .earlySingletonObjects.remove(beanName);

                 添加到已经注册的singleton实例.
                .registeredSingletons.add(beanName);
            }
        }
    }

什么时候执行的呢? 再从缓存中获取对象的时候. 

@Nullable
    protected Object  从一级缓存中获取bean实例对象
        Object singletonObject = (beanName);
        *
         * 如果在第一级的缓存中没有获取到对象,并且singletonsCurrentlyIncreation为true,也就是这个类正在创建.
         * 标明当前是一个循环依赖.
         *
         * 这里有处理循环依赖的问题.-- 我们使用三级缓存解决循环依赖
         */
        null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (.singletonObjects) {
                *
                 * 从二级缓存中拿bean,二级缓存中的对象是一个早期对象
                 * 什么是早期对象?就是bean刚刚调用了构造方法,还没有给bean的属性进行赋值,和初始化,这就是早期对象
                  */

                singletonObject = this.earlySingletonObjects.(beanName);
                 allowEarlyReference) {
                    *
                     * 从三级缓存拿bean,singletonFactories是用来解决循环依赖的关键所在.
                     * 在ios后期的过程中,当bean调用了构造方法的时候,把早期对象包装成一个ObjectFactory对象,暴露在三级缓存中
                      */
                    ObjectFactory<?> singletonFactory = this.singletonFactories.(beanName);
                    if (singletonFactory != ) {
                        /**
                         * 在这里通过暴露的ObjectFactory包装对象. 通过调用他的getObject()方法获取对象
                         * 在这个环节中会调用getEarlyBeanReference()来进行后置处理
                         */
                        singletonObject = singletonFactory.getObject();
                         把早期对象放置在二级缓存中
                        .earlySingletonObjects.put(beanName,singletonObject);
                         删除三级缓存
                        .singletonFactories.remove(beanName);
                    }
                }
            }
        }
         singletonObject;
    }

在这里调用三级缓存, singletonObject = singletonFactory.getObject(); 回调钩子函数

猜你在找的Spring相关文章