【Spring IOC】【二】容器源码解析- 获取单例 Bean

1  前言

在本篇文章中,我们将会详细分析BeanFactorygetBean(String)方法实现细节及所调用的方法。

2  源码分析

首先我们先通读一下doGetBean方法,了解里边重点的几个步骤,然后我们再分析每个步骤里边具体都做了什么。

2.1  方法通读

方法的注释都写在里边了,涉及的东西也挺多的,耐心看。

  1 protected <T> T doGetBean(
  2             String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
  3             throws BeansException {
  4         /*
  5          * 转换name  也就是我们参数给的name 要转换成Spring自己的beanName
  6          * 这么做的原因: 1、bean的名字不唯一,比如还有别名,那么一个beanName这么多名字,Spring自己处理逻辑的时候只会用一个名字来贯穿它的整个逻辑 是不是
  7          *                 所以不管你给的名字是别名还是正常的名字 都要转换成它本身逻辑中唯一的那个beanName
  8          *               2、name 可能会以 & 字符开头, 就是要获取FactoryBean即创建Bean的那个对象,而不是获取Bean,
  9          *                 而Bean和创建Bean的对象也是以beanName->ObjectFactory这样的键值对存在,所以要转成它的beanName 其实就是去前缀&
 10          */
 11         String beanName = transformedBeanName(name);
 12         Object beanInstance;
 13         /*
 14          * 从单例缓存中获取Bean,下边会细讲
 15          */
 16         Object sharedInstance = getSingleton(beanName);
 17         /*
 18          * 如果 sharedInstance = null,则说明缓存里没有对应的实例,表明这个实例还没创建。
 19          * BeanFactory 并不会在一开始就将所有的单例bean实例化好,而是在调用getBean获取bean时再实例化,也就是懒加载。
 20          * sharedInstance!=null 说明我已经拿到bean了  并且这个bean是单例的
 21          */
 22         if (sharedInstance != null && args == null) {
 23             if (logger.isTraceEnabled()) {
 24                 if (isSingletonCurrentlyInCreation(beanName)) {
 25                     logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
 26                             "' that is not fully initialized yet - a consequence of a circular reference");
 27                 }
 28                 else {
 29                     logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
 30                 }
 31             }
 32             /*
 33              * 这个方法是要处理 比如你获取的不是bean 而是获取bean的FactoryBean 所以这个方法给你做处理
 34              */
 35             beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 36         }
 37         /*
 38          * 走到这里说明缓存中没有bean并且bean也没有被创建
 39          * 什么情况下会走到这里呢?
 40          * 比如 当第一次去获取一个bean不管是单例或者多例的时候 都会走到这里
 41          */
 42         else {
 43             /*
 44              * Fail if we're already creating this bean instance:
 45              * We're assumably within a circular reference.
 46              * 判断这个bean 是不是当前正在创建中的并且是多例的话 我要报异常 因为多例的循环依赖无法解决
 47              */
 48             if (isPrototypeCurrentlyInCreation(beanName)) {
 49                 throw new BeanCurrentlyInCreationException(beanName);
 50             }
 51             /*
 52              * 这里会获取当前BeanFactory的父BeanFactory 有点跟那个类加载机制的委派机制有点类似
 53              * 我们暂时知道BeanFactory有父子嵌套的关系即可 后续再详解 有个重要的DefaultListableBeanFactory
 54              * Check if bean definition exists in this factory.
 55               */
 56             BeanFactory parentBeanFactory = getParentBeanFactory();
 57             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 58                 /*
 59                  * 由父类BeanFactory去创建bean
 60                  */
 61                 String nameToLookup = originalBeanName(name);
 62                 if (parentBeanFactory instanceof AbstractBeanFactory) {
 63                     return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
 64                             nameToLookup, requiredType, args, typeCheckOnly);
 65                 }
 66                 else if (args != null) {
 67                     // Delegation to parent with explicit args.
 68                     return (T) parentBeanFactory.getBean(nameToLookup, args);
 69                 }
 70                 else if (requiredType != null) {
 71                     // No args -> delegate to standard getBean method.
 72                     return parentBeanFactory.getBean(nameToLookup, requiredType);
 73                 }
 74                 else {
 75                     return (T) parentBeanFactory.getBean(nameToLookup);
 76                 }
 77             }
 78 
 79             if (!typeCheckOnly) {
 80                 markBeanAsCreated(beanName);
 81             }
 82 
 83             StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
 84                     .tag("beanName", name);
 85             try {
 86                 if (requiredType != null) {
 87                     beanCreation.tag("beanType", requiredType::toString);
 88                 }
 89                 /*
 90                  * 合并父BeanDefinition 和 子BeanDefinition 后边讲解
 91                  */
 92                 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 93                 checkMergedBeanDefinition(mbd, beanName, args);
 94 
 95                 /*
 96                  * 这里是检查bean 有没有dependsOn 就是依赖别的bean 有的话 循环去初始化bean
 97                  * Guarantee initialization of beans that the current bean depends-on.
 98                  */
 99                 String[] dependsOn = mbd.getDependsOn();
100                 if (dependsOn != null) {
101                     for (String dep : dependsOn) {
102                         /*
103                          * depends-on 不能互相依赖 比如a的depends-on里有b 创建b 发现b的depends-on里又有a 就报错
104                          */
105                         if (isDependent(beanName, dep)) {
106                             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
107                                     "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
108                         }
109                         /*
110                          * 把这种依赖关系保存起来
111                          */
112                         registerDependentBean(dep, beanName);
113                         try {
114                             /*
115                              * 去创建或者获取依赖的bean 有点递归的意思
116                              */
117                             getBean(dep);
118                         }
119                         catch (NoSuchBeanDefinitionException ex) {
120                             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
121                                     "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
122                         }
123                     }
124                 }
125                 /*
126                  * bean 是否是单例的
127                  * Create bean instance.
128                  */
129                 if (mbd.isSingleton()) {
130                     /*
131                      * 这里并没有直接调用 createBean 方法创建 bean 实例,而是通过
132                      * getSingleton(beanName, ObjectFactory)方式创建  ObjectFactory是个函数接口
133                      * 其实就是调用getObject方法 后续会详解
134                      */
135                     sharedInstance = getSingleton(beanName, () -> {
136                         try {
137                             return createBean(beanName, mbd, args);
138                         }
139                         catch (BeansException ex) {
140                             // Explicitly remove instance from singleton cache: It might have been put there
141                             // eagerly by the creation process, to allow for circular reference resolution.
142                             // Also remove any beans that received a temporary reference to the bean.
143                             destroySingleton(beanName);
144                             throw ex;
145                         }
146                     });
147                     // 这里也是一样 如果获取的是FactoryBean 进行结果转换
148                     beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
149                 }
150                 // 多实例的创建
151                 else if (mbd.isPrototype()) {
152                     // It's a prototype -> create a new instance.
153                     Object prototypeInstance = null;
154                     try {
155                         beforePrototypeCreation(beanName);
156                         prototypeInstance = createBean(beanName, mbd, args);
157                     }
158                     finally {
159                         afterPrototypeCreation(beanName);
160                     }
161                     beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
162                 }
163                 // 其它类型的scope创建
164                 else {
165                     String scopeName = mbd.getScope();
166                     if (!StringUtils.hasLength(scopeName)) {
167                         throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
168                     }
169                     Scope scope = this.scopes.get(scopeName);
170                     if (scope == null) {
171                         throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
172                     }
173                     try {
174                         Object scopedInstance = scope.get(beanName, () -> {
175                             beforePrototypeCreation(beanName);
176                             try {
177                                 return createBean(beanName, mbd, args);
178                             }
179                             finally {
180                                 afterPrototypeCreation(beanName);
181                             }
182                         });
183                         beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
184                     }
185                     catch (IllegalStateException ex) {
186                         throw new ScopeNotActiveException(beanName, scopeName, ex);
187                     }
188                 }
189             }
190             catch (BeansException ex) {
191                 beanCreation.tag("exception", ex.getClass().toString());
192                 beanCreation.tag("message", String.valueOf(ex.getMessage()));
193                 cleanupAfterBeanCreationFailure(beanName);
194                 throw ex;
195             }
196             finally {
197                 beanCreation.end();
198             }
199         }
200         // 这里就是进行一个类型转换
201         return adaptBeanInstance(name, beanInstance, requiredType);
202     }
View Code

大概的一个执行流程如下:

(1)参数名称转换  也就是转换成Spring自己对每个Bean保留的唯一beanName

(2)先从缓存中拿,能拿到就返回,没有则继续

(3)判断当前bean工厂有没有父级工厂,有的话且当前工厂没有bean的BeanDefinition就由父工厂去创建bean

(4)合并父亲和当前工厂的对该bean的BeanDefinition

(5)处理下depends-on依赖,有的话循环创建依赖的bean

(6)根据bean的scope属性值(默认单例)去创建并缓存bean

(7)getObjectForBeanInstance 是获取bean还是beanFactory的判断处理

(8)按需转换bean类型

2.2  从缓存中获取 bean 实例

对于单例 bean,Spring 容器只会实例化一次。后续再次获取时,只需直接从缓存里获取即可,无需且不能再次实例化(否则单例就没意义了)。从缓存中取 bean 实例的方法是getSingleton(String),下面我们就来看看这个方法实现方式吧。如下:

/*
        单例bean的获取
        这里会涉及到几个map 一方面缓存 一方面解决循环引用的后续讲解挺有意思的
        常说的 三级缓存解决循环依赖的
        singletonObjects  这个里边存的都是完整的bean 拿来就可以用的  一级缓存
        earlySingletonObjects 这个里边存的是创建中 还不完整的bean    二级缓存
        singletonFactories  这个路边存的是 bean->ObjectFactory 也就是bean和用于创建bean的工厂 三级缓存
     */
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        // 先从完整的里边拿, 有的话就返回 没有的话继续
        Object singletonObject = this.singletonObjects.get(beanName);
        // 完整缓存中没有bean 并且当前这个bean正在创建中继续  没有在创建中的话返回
        // isSingletonCurrentlyInCreation 为什么要有这个判断  解决循环依赖的
        // 比如 A需要B B需要A  A在创建的时候 需要找B  B就需要创建发现B又需要A 这时isSingletonCurrentlyInCreation就为true了
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // 从二级缓存中获取提前曝光的 bean
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 如果 singletonObject = null,且允许提前曝光 bean 实例,则从相应的 ObjectFactory得到一个原始的bean(尚未填充属性)
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    //得到bean的工厂
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        // 单例双重检查
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            // 创建bean 并放入二级缓存 并清理掉三级缓存
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }

2.3  合并父 BeanDefinition 与子 BeanDefinition

Spring 支持配置继承,在 <bean/> 标签中可以使用parent属性配置父类 bean。这样子类 bean 可以继承父类 bean 的配置信息,同时也可覆盖父类中的配置。比如下面的配置:

<bean id="demoBean" class="com.virtuous.demo.spring.DemoBean">
  <property name="content" value="我是父亲content"/>
  <property name="remark" value="我是父亲remark"/>
</bean>
<bean id="cat" class="com.virtuous.demo.spring.Cat" parent="demoBean" >
  <property name="remark" value="我是儿子remark"/>
</bean>

由测试结果可以看出,子类继承了父亲的content属性值,并覆盖了父亲的remark值,看完代码演示,接下来我们来看看源码吧。如下:

// 调用入口
    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
        // 缓存中有没有 有就直接返回
        RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
        if (mbd != null && !mbd.stale) {
            return mbd;
        }
        // 调用重载方法
        return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    }

    //继续
    protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
            throws BeanDefinitionStoreException {
        // 调用重载方法
        return getMergedBeanDefinition(beanName, bd, null);
    }
    // 合并的核心代码
    protected RootBeanDefinition getMergedBeanDefinition(
            String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
            throws BeanDefinitionStoreException {
        // 上锁
        synchronized (this.mergedBeanDefinitions) {
            RootBeanDefinition mbd = null;
            // 结合mbd.stale 如果合并过 previous记录合并前的旧值
            RootBeanDefinition previous = null;
            // containingBd 这个还真不知道起的啥作用 等待
            if (containingBd == null) {
                mbd = this.mergedBeanDefinitions.get(beanName);
            }
            // stale 加了可见性属性
            if (mbd == null || mbd.stale) {
                previous = mbd;
                // 无父BeanDefinition
                if (bd.getParentName() == null) {
                    if (bd instanceof RootBeanDefinition) {
                        mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                    }
                    else {
                        mbd = new RootBeanDefinition(bd);
                    }
                }
                else {
                    BeanDefinition pbd;
                    try {
                        // 获取bean的parent beanName  拿上边举的例子来说 demoBean的parentBeanName=cat
                        String parentBeanName = transformedBeanName(bd.getParentName());
                        // demoBean != cat  则先合父亲cat的 递归的往上合并 cat要是还有父亲继续递归等
                        if (!beanName.equals(parentBeanName)) {
                            pbd = getMergedBeanDefinition(parentBeanName);
                        }
                        else {
                            // 感觉这个应该时spring给自己做冗余的方法
                            // 获取父容器,并判断,父容器的类型,若不是 ConfigurableBeanFactory 则判抛出异常
                            BeanFactory parent = getParentBeanFactory();
                            if (parent instanceof ConfigurableBeanFactory) {
                                pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                            }
                            else {
                                throw new NoSuchBeanDefinitionException(parentBeanName,
                                        "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                                "': cannot be resolved without a ConfigurableBeanFactory parent");
                            }
                        }
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                    }
                    // 到这里以父亲为基准创建RootBeanDefinition
                    mbd = new RootBeanDefinition(pbd);
                    // 然后再把当前的bd覆盖一遍完事
                    mbd.overrideFrom(bd);
                }

                // 如果用户未配置 scope 属性,则默认将该属性配置为 singleton  这就是默认的singleton
                if (!StringUtils.hasLength(mbd.getScope())) {
                    mbd.setScope(SCOPE_SINGLETON);
                }

                if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                    mbd.setScope(containingBd.getScope());
                }

                // 放进缓存中
                if (containingBd == null && isCacheBeanMetadata()) {
                    this.mergedBeanDefinitions.put(beanName, mbd);
                }
            }
            if (previous != null) {
                copyRelevantMergedBeanDefinitionCaches(previous, mbd);
            }
            return mbd;
        }
    }

2.4  从 FactoryBean 中获取 bean 实例

 FactoryBean 是一种工厂 bean,与普通的 bean 不一样,FactoryBean 是一种可以产生 bean 的 bean,当我们调用 getBean("dogFactoryBean") 时,ApplicationContext 会返回一个 Dog对象,该对象是 DogFactoryBean 的 getObject 方法所创建的。如果我们想获取 DogFactoryBean 本身,则可以在 dogFactoryBean前加上一个前缀&,即&dogFactoryBean

<bean id="cat" class="com.virtuous.demo.spring.Cat" parent="demoBean"/>  提供的是对象的类
<bean id="dogFactoryBean" class="com.virtuous.demo.spring.DogFactoryBean"/> 提供的是创建对象的FactoryBean
// 提供了一个FactoryBean 给到Spring
public class DogFactoryBean implements FactoryBean<Dog> {
    @Override
    public Dog getObject() throws Exception {
        return new Dog();
    }

    @Override
    public Class<?> getObjectType() {
        return Dog.class;
    }
}

getObjectForBeanInstance方法会对返回的bean做一层处理,还挺绕的,相关的源码如下:

/**
     * 这个方法刚开始我有点懵  我寻思是从bean身上拿beanFactory
     * 比如我提供了Cat对象给Spring管理, getBean的时候参数cat  Spring给我一个Cat对象
     *                                              参数&cat Spring给我Cat对象的FactoryBean
     * 这个想法是错的错的!!!!
     * 当你提供给Spring的是FactoryBean类型的 Spring才会&cat 返回给你FactoryBean对象
     * 并且三个缓存里放置的也都是你提供的FactoryBean
     * 当你 cat 或者 &cat 下边这个方法会根据你的名字返回给你对应的对象
     * 仔细想想 好好想想这个方法
     */
    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

        /*
            判断是不是&开头  &就是要获取FactoryBean
            这个if 会把name是&开头的处理返回掉
         */
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            // 为空Bean 就返回
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
            // 发现beanInstance不是一个FactoryBean就报错 也就是你提供的不是一个FactoryBean
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            // 这个小细节不知道是干啥的
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            return beanInstance;
        }

        /*
         * 走到这里 name就是要获取正常的bean对象 因为上边if已经把&开头的处理掉了
         * 而beanInstance 可能是个bean 也可能是个factoryBean
         * 因为当你提供的是个factoryBean 这里就是factoryBean
         */
        // 因为你要获取的是bean,这里发现beanInstance 不是一个FactoryBean 就是beanInstance 已经是个bean了 就返回
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        else {
            /*
             * 如果 mbd 为空,则从缓存中加载 bean。FactoryBean 生成的单例 bean 会被缓存
             * 在 factoryBeanObjectCache 集合中,不用每次都创建
             */
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // 经过前面的判断,到这里可以保证 beanInstance 是 FactoryBean 类型的,所以可以进行类型转换
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // 如果 mbd 为空,则判断是否存在名字为 beanName 的 BeanDefinition
            if (mbd == null && containsBeanDefinition(beanName)) {
                // 合并 BeanDefinition
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            /* synthetic 字面意思是"合成的"。通过全局查找,我发现在 AOP 相关的类中会将该属性设为 true。
             * 所以我觉得该字段可能表示某个 bean 是不是被 AOP 增强过,也就是 AOP 基于原始类合成了一个新的代理类。
             * 不过目前只是猜测,没有深究。
             */
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            // 调用 getObjectFromFactoryBean 方法继续获取实例 里边会涉及后置处理aop
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

上面的源码分析完了,代码虽长,但整体逻辑不是很复杂,这里简单总结一下。getObjectForBeanInstance 及它所调用的方法主要做了如下几件事情:

  1. 检测参数 beanInstance 的类型,如果是非 FactoryBean 类型的 bean,直接返回
  2. 检测 FactoryBean 实现类是否单例类型,针对单例和非单例类型进行不同处理
  3. 对于单例 FactoryBean,先从缓存里获取 FactoryBean 生成的实例
  4. 若缓存未命中,则调用 FactoryBean.getObject() 方法生成实例,并放入缓存中
  5. 对于非单例的 FactoryBean,每次直接创建新的实例即可,无需缓存
  6. 如果 shouldPostProcess = true,不管是单例还是非单例 FactoryBean 生成的实例,都要进行后置处理

3  小结

看源码真的是太费脑细胞了,里边的一些小细节设计真的是秒,可以看到单例双重检查锁很常见,耐心看,多看几遍,就这个我至少看了5遍才大概懂了,看不懂的要多想想,还有好多东西要看,继续下一部分,加油。

posted @ 2023-02-15 15:16  酷酷-  阅读(97)  评论(0编辑  收藏  举报