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

第一篇: 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(包装为早期对象)
     */
    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(); 回调钩子函数. 

11-15 16:58