从上篇文章中我们可以得知,如果从单例缓存中没有获取到单例bean,则会说明是下面俩种情况发生:
- 该bean的scope是singleton ,但是没有初始化完成
- 该bean的scope不是singleton
本篇文章就来进行这部分的分析,这里先讲循环依赖检测、parentBeanFactory与依赖处理,剩下的scope处理,主要在下一篇文章中讲解。
本文所分析的具体源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } }
if (!typeCheckOnly) { markBeanAsCreated(beanName); }
try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { 。。。。省略异常 } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { 省略异常 } } }
|
这段代码主要处理流程如下:
- 检测当前beanName对应的bean是否是Prototype循环依赖,如果是,则抛出BeanCurrentlyInCreationException异常。
- 如果beanDefinitionMap中不存在beanName对应的BeanDefinition,前面说过BeanFactory是有继承体系的,可以从父BeanFactory中获取,也即是上面尝试从parentBeanFactory中加载。
- 判断是否为类型检查,如果不是,需要标记处理。
- 从mergedBeanDefinitions中获取beanName对应的RootBeanDefinition,如果这个BeanDefinition是子Bean的话,则会合并父类的相关属性。
- 依赖处理,这里的依赖是指depend-on属性指定的依赖,和后面说道的内部依赖不一样。
检测当前bean是否是Prototype类型的循环依赖
在前面就提过,Spring只解决单例模式下的循环依赖,对于原型模式的循环依赖则是抛出BeanCurrentlyInCreationException异常,所以首先检查该beanName是否处于原型模式下的循环依赖。如下:
1 2 3
| if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
|
调用isPrototypeCurrentlyInCreation()
判断当前bean是否正在创建,如下:
1 2 3 4 5 6
| protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); }
|
其实检测逻辑和单例模式一样,一个集合存放着正在创建的bean,从该集合中进行判断即可,只不过单例模式的集合为Set全局共享,而原型模式的则是ThreadLocal,线程私有,这也比较好理解,因为原型毕竟在需要的时候在创建,而且每个线程处理不同的逻辑,所以需要不同的对象,因此用ThreadLocal拉保存当前线程对应的正在创建的bean实例。prototypesCurrentlyInCreation定义如下:
1 2
| private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation");
|
这里只是判断,你可能会疑惑这是什么时候加入进去的。后面再讲创建不同作用域的bean实例时会说到。
检查父类BeanFactory
若 containsBeanDefinition
中不存在beanName相对应的BeanDefinition,则从parentBeanFactory中获取,这个是因为BeanFactory是可以有集成体系。源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else { return parentBeanFactory.getBean(nameToLookup, requiredType); } }
|
整个过程较为简单,都是委托 parentBeanFactory的getBean()
进行处理,只不过在获取之前对name进行简单的处理,主要是想获取原始的beanName,也就是传进来的name如下:
1 2 3 4 5 6 7
| protected String originalBeanName(String name) { String beanName = transformedBeanName(name); if (name.startsWith(FACTORY_BEAN_PREFIX)) { beanName = FACTORY_BEAN_PREFIX + beanName; } return beanName; }
|
transformedBeanName()
是对 name 进行转换,获取真正的 beanName,因为我们传递的可能是 aliasName(这个过程在上一篇博客中分析 transformedBeanName()
有详细说明),如果 name 是以 “&” 开头的,则加上 “&”,因为在 transformedBeanName()
将“&” 掉了,这里加上。
类型检查
参数 typeCheckOnly 是用来判断调用getBean()
是否为类型检查获取bean。如果不是仅做类型检查则是创建bean,则需要调用markBeanAsCreated()
记录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| protected void markBeanAsCreated(String beanName) { if (!this.alreadyCreated.contains(beanName)) { synchronized (this.mergedBeanDefinitions) { if (!this.alreadyCreated.contains(beanName)) { clearMergedBeanDefinition(beanName); this.alreadyCreated.add(beanName); } } } }
|
获取RootBeanDefinition
1
| final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
调用 getMergedLocalBeanDefinition()
获取相对应的 BeanDefinition,如下:
1 2 3 4 5 6 7 8 9 10 11
| protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); if (mbd != null) { return mbd; } return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); }
|
首先直接从mergedBeanDefinitions缓存中获取相应的RootBeanDefinition,如果存在则直接返回,不存在则调用getMergedBeanDefinition()
获取RootBeanDefinition,若获取的BeanDefinition为子BeanDefinition,则需要合并父类的相关属性。具体的合并过程这里就不细说,如果你感兴趣的话可以仔细研究。
处理depend-on依赖
如果一个bean有依赖bean的话,那么在初始化该bean时是需要先初始化它所依赖的bean。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { 。。。。异常 } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { 。。。。省略异常 } } }
|
这段代码逻辑是:通过迭代的方式依次对依赖bean进行检测、校验,如果检测通过,则调用getBean()
实例化依赖bean。
isDependent()
是校验是否存在循环依赖,也就是A->B,B->C,C->A这种情况。
1 2 3 4 5
| protected boolean isDependent(String beanName, String dependentBeanName) { synchronized (this.dependentBeanMap) { return isDependent(beanName, dependentBeanName, null); } }
|
同步加锁给dependentBeanMap对象,然后调用isDependent()
校验。dependentBeanMap对象保存的是依赖之间的映射关系:beanName–>依赖beanName的集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) { if (alreadySeen != null && alreadySeen.contains(beanName)) { return false; } String canonicalName = canonicalName(beanName); Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName); if (dependentBeans == null) { return false; } if (dependentBeans.contains(dependentBeanName)) { return true; } for (String transitiveDependency : dependentBeans) { if (alreadySeen == null) { alreadySeen = new HashSet<>(); } alreadySeen.add(beanName); if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) { return true; } } return false; }
|
如果不存在循环依赖,则调用registerDependentBean()
将该依赖进行记录,便于在销毁依赖bean之前对其进行销毁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName);
synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { return; } }
synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } }
|
其实将就是该映射关系保存到两个集合中:dependentBeanMap、dependenciesForBeanMap。
最后调用getBean()
实例化依赖bean。
至此,加载bean的第二个部分也分析完毕了,下篇开始分析第三个部分:不同作用域bean的创建。