zoukankan      html  css  js  c++  java
  • Spring源码分析(十三)缓存中获取单例bean

    摘要:本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

    介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了。前面已经提到过,单 例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再尝试从singletonFactories中加载。 因为在创建单例bean的时候会存在依赖注人的情况,而在创建依赖的时候为了避免循环依赖, Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加人到 缓存中,一旦下一个bean创建时需要依赖上个bean,则直接使用ObjectFactory。

    @Override
    @Nullable
    public Object getSingleton(String beanName) {
        // 参数true设置标识允许早期依赖
        return getSingleton(beanName, true);
    }
    
    /**
     * Return the (raw) singleton object registered under the given name.
     * <p>Checks already instantiated singletons and also allows for an early
     * reference to a currently created singleton (resolving a circular reference).
     * @param beanName the name of the bean to look for
     * @param allowEarlyReference whether early references should be created or not
     * @return the registered singleton object, or {@code null} if none found
     */
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 检査缓存中是否存在实例
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // 如果为空,则锁定全局变量并进行处理
            synchronized (this.singletonObjects) {
                // 如果此bean正在加载则不处理
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    // 当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策路存储在 singletonFactories
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        // 调用预先设定的getObject方法
                        singletonObject = singletonFactory.getObject();
                        // 记录在缓存中,earlySingletonObjects和singletonFactories互斥
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

    这个方法因为涉及循环依赖的检测,以及涉及很多变量的记录存取,所以让很多读者摸不着头脑。这个方法首先尝试从singletonObjects面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject 来创建bean,并放到 earlySingletonObjects里面去,并且从singletonFacotories里面remove掉这个ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在allowEarlyReference为true的情况下才会使用。
    这甩涉及用于存储bean的不同的map,可能让读者感到崩溃,简单解释如下。

    singletonObjects 用于保存 beanName 和创建 bean 实例之间的关系,bean name -> bean instance
    singletonFactories 用于保存beanName 和创建bean的工厂之间的关系,bean name -> ObjectFactory
    earlySingletonObjects 也是保存beanName 和创建bean实例之间的关系,与 singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检測循环引用
    registeredSingletons 用来保存当前所有已注册的bean
  • 相关阅读:
    LeetCode 842. Split Array into Fibonacci Sequence
    LeetCode 1087. Brace Expansion
    LeetCode 1219. Path with Maximum Gold
    LeetCode 1079. Letter Tile Possibilities
    LeetCode 1049. Last Stone Weight II
    LeetCode 1046. Last Stone Weight
    LeetCode 1139. Largest 1-Bordered Square
    LeetCode 764. Largest Plus Sign
    LeetCode 1105. Filling Bookcase Shelves
    LeetCode 1027. Longest Arithmetic Sequence
  • 原文地址:https://www.cnblogs.com/warehouse/p/9381824.html
Copyright © 2011-2022 走看看