3.4 spring5源码系列--循环依赖的设计思想

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

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

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

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

如今总结循环依赖的思想多线程

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

思想才是咱们能够在工做中借鉴使用的

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

2. 接口函数源码分析

 


 

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

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

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(包装为早期对象)
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name to bean instance. */
    /**
     * 二级缓存, 用户缓存咱们的key为beanName, value是咱们的早期对象(此时对象属性尚未...)
     */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(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 (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName,
                            "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 == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    // 第三步: 这里调用getObject()钩子方法, 就会回调匿名函数, 调用singletonFactory的createBean() singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {
                    // Has the singleton object implicitly appeared in the meantime ->
                    // if yes, proceed with it since the exception indicates that state.
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw ex;
                    }
                }
                catch (BeanCreationException ex) {
                    if (recordSuppressedExceptions) {
                        for (Exception suppressedException : this.suppressedExceptions) {
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                }
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

 

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

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

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

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

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);

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

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

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

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

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

相关文章
相关标签/搜索