【Spring IOC】【二】容器源码解析- 获取单例 Bean
1 前言
在本篇文章中,我们将会详细分析BeanFactory
的getBean(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 }
大概的一个执行流程如下:
(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 及它所调用的方法主要做了如下几件事情:
- 检测参数 beanInstance 的类型,如果是非 FactoryBean 类型的 bean,直接返回
- 检测 FactoryBean 实现类是否单例类型,针对单例和非单例类型进行不同处理
- 对于单例 FactoryBean,先从缓存里获取 FactoryBean 生成的实例
- 若缓存未命中,则调用 FactoryBean.getObject() 方法生成实例,并放入缓存中
- 对于非单例的 FactoryBean,每次直接创建新的实例即可,无需缓存
- 如果 shouldPostProcess = true,不管是单例还是非单例 FactoryBean 生成的实例,都要进行后置处理
3 小结
看源码真的是太费脑细胞了,里边的一些小细节设计真的是秒,可以看到单例双重检查锁很常见,耐心看,多看几遍,就这个我至少看了5遍才大概懂了,看不懂的要多想想,还有好多东西要看,继续下一部分,加油。