回顾
前面我们已经看过了对于XML中的bean、alias、import、beans标签的解析
现在IOC容器中已经有着bean的配置了,下面就来看看,在Spring中,是如何加载这些配置的
bean的加载
bean的加载远远比解析xml文件要难,首先我们来看一下Spring中是如何获取bean的
从官网上可以看到,使用getBean方法就可以获取到实例Bean了
getBean方法
getBean的方法是位于BeanFactory接口里面的
这里中调用的是AbstractBeanFactory的getBean
并且具体的实现在doGetBean方法里面
doGetBean方法
源码如下
- name:指定的beanName
- requiredType:指定的beanType
- args:实例化bean时使用的参数
- typeCheckOnly:实例化bean是否开启类型检查
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//将name转化为beanName,因为进来的name可能是别名
//beanName就会从aliasMap中获取,aliasMap就是存放别名的容器
String beanName = transformedBeanName(name);
Object beanInstance;
//这一步是避免循环依赖的问题
//假设A中有B的属性,而B中有A的属性
//当依赖注入时,就会产生A还没创建完,就会因为去注入B,导致去创建B
//而创建B的时候由因为去注入A,从而再次去创建A,造成一个循环问题
//会从singletonObjects(单例实例工厂)和earlySingletonObjects(单例缓存)中去根据beanName去获取bean
//并且在方法里面,如果找不到,是会添加进earlySingletonObjects(单例缓存)中去的
//也就是说bean还没有创建完,就会提前将bean的ObjectFactory暴露出来
//比如当前的bean还没创建,就会提前存入缓存中进行暴露
//当下个bean创建时需要依赖上个bean则直接使用ObjectFactory
Object sharedInstance = getSingleton(beanName);
//假如缓存中或者实例工厂中存在该bean,并且没有给创建bean的参数
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
//判断该bean是不是已经创建过,通过beanName去判断
//而且这里的判断是判断创建的单例bean,从前面创建的单例bean中
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//从实例工厂中或者本身实例中获取bean实例
//也就是说beanInstance可能是实例工厂中创建,也可能直接为sharedInstance
//这样就解决了单例情况的循环依赖问题,当创建B时去注入属性A时,会从单例缓存或单例工厂中直接取原来的A
//这样就不会创建另一个A了,解决了单例的循环依赖问题
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//如果单例缓存中或者实例工厂中不存在该bean
//证明是原型模式创建该bean
else {
//判断是否出现了循环依赖问题
//上面是解决单例模式的循环依赖,而这里是判断在原型模式情况下是否出现了循环依赖
//判断beanName对应的bean在缓存中是否已经存在
if (isPrototypeCurrentlyInCreation(beanName)) {
//如果已经在创建,抛错
//所以Spring是不会解决原型模式的循环依赖
throw new BeanCurrentlyInCreationException(beanName);
}
//判断beanName对应的bean是不是已经在工厂中创建
//获取工厂
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果工厂不为空,且IOC容器里面不包含这个bean
//一般来说只要配置正确是不会走这里的
//这里是针对在bean标签中引用了其他bean,但其他bean并没有实例化
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
//判断是否需要类型检查
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
//使用IOC容器中的beanDefinition创建RootBeanDefinition
//但此时该bean是还没有创建好的,因为存在依赖注入其他bean的问题
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 获取该bean需要依赖的其他bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
//遍历所有依赖的bean
for (String dep : dependsOn) {
//这一步就是判断当前bean与依赖的bean是否有循环依赖
//在里面是有一个容器去存储正在依赖的bean的
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//如果不存在循环依赖问题就进行注册
registerDependentBean(dep, beanName);
try {
//这里调用getBean方法去获取依赖的bean
//这里产生了递归,getBean仍然会去调用doGetBean方法
//所以循环依赖的检查通过递归、三级缓存和提前暴露去检查出来
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//通过上面的检测已经检测出该bean是否出现循环依赖问题了
//下面就可以正式创建bean了
// Create bean instance.
// 如果当前创建的bean是单例模式
if (mbd.isSingleton()) {
//使用单例模式进行创建bean
sharedInstance = getSingleton(beanName, () -> {
try {
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;
}
});
//创建beanInstance
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 如果当前创建的bean是原型模式
else if (mbd.isPrototype()) {
//使用原型模式来创建bean
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 其他模式下创建bean
else {
//其他模式下创建bean
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
//创建beanInstance
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
//最终释放缓存
beanCreation.end();
}
}
//使用得到的beanInstace去创建bean
return adaptBeanInstance(name, beanInstance, requiredType);
}
总结一下加载bean的过程
-
通过name获取真实的beanName(SimpleAliasRegistry里面的aliasMap中寻找,前面学习alias标签注册的时候使用过这个容器)
- 别名转换为beanName
- 取出FactoryBean的修饰符,因为FactoryBean前面都带有一个&,要将&去除掉
-
判断当前是否出现单例Bean的循环依赖
- Spring对于单例bean的创建只会创建一次,以后使用到该bean时都是直接从单例缓存中取的
- Spring采用三级缓存+提前曝光的形式去创建bean,就是该bean还没创建完(存在依赖注入其他bean),该bean就会被添加进缓存中,因为Spring规定了必须将依赖的bean加载完了,才能去加载父bean
- 这里会优先从单例bean的缓存中尝试看能不能加载bean
- 如果能加载出来,证明出现了循环依赖了
- 那么会直接将缓存的bean返回(解决了单例的循环依赖)
-
如果单例缓存中加载不出来,那就证明没有单例的循环依赖,接下来判断是不是原型的循环依赖
- Spring是不会去对原型模式的循环依赖进行解决的,一旦发现是原型模式的循环依赖是会直接抛错的,因为原型模式每次进行使用都会去创建一个新的bean,所以原型模式没有自己的缓存(每次都去创建新的,用缓存干嘛)
- 不过在创建Bean时,也是会利用缓存的,因为判断是否出现循环依赖的问题是使用的提前曝光
- 如果没有出现循环依赖问题,才开始去创建bean
- 单例模式创建bean
- 原型模式创建bean
- 其他模式创建bean
-
最后就是进行类型转换,使用转换器对创建去的bean转化为想要的类型,这也是为什么使用context去getBean时要提供class方法
从缓存中获取单例bean
下面就来看下单例的缓存,这也是解决单例出现循环依赖的关键之处
要注意的是此时该bean还没有创建完,这一步也是进行提前曝光的
getSingleton
对应的代码为下面这一部分
而具体从缓存中去获取单例bean的是在getSingleton方法里面,并且可以看到,单例缓存是交由DefaultSingletonBeanRegistry负责的
该方法调用了getSingleton方法,并且将allowEarlyReference的参数设置为true,这个参数是是否进行提前曝光的,这里设置为true,就代表进行提前曝光
看源码前,必须先认识这里的5个容器
三级缓存是指下面这三个
- 一级缓存:singletonObjects,存储所有的单例bean
- 二级缓存:earlySingletonObjects,存储提前暴露的bean,里面的bean都是没创建完的
- 三级缓存:singletonFactories,存储单例bean的ObjectFactory(也就是创建该bean的工厂)
- registeredSingletons:存储创建好的单例Bean的beanName,可以用这个来判断beanName是否已经创建了
- singletonsCurrentlyInCreation:存储正在创建的单例bean的beanName,可以用这个来判断指定beanName是不是正在创建
源码如下
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 判断一级缓存中是否有该bean,一级缓存就是创建好的所有单例bean
// 所以一级缓存中bean出现的话,直接用就好了
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//如果一级缓存中没有,并且判断这个bean是不是正在创建中
//这里存储正在创建中和的单例beans底层容器是一个set集合
//从二级缓存中去获取bean
singletonObject = this.earlySingletonObjects.get(beanName);
//如果二级缓存中没有,并且允许进行提前暴露
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
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//通过ObjectFactory取创建bean
singletonObject = singletonFactory.getObject();
//并且将该bean存放进二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
//因为二级缓存中有该bean了,所有不需要三级缓存了
//从三级缓存中移除这个bean
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
//返回单例bean
return singletonObject;
}
总结一下这个方法
-
判断一级缓存中是否已经有这个bean(之前是否已经创建好了)
- 有的话直接使用
-
一级缓存中没有该bean,并且该bean是正在创建中的
- 从二级缓存中取出该bean,看是否已经提前暴露了
-
二级缓存中没有该bean,并且允许进行提前暴露
- 给一级缓存进行上锁,开始逐层缓存去获取bean,因为只要给一级缓存上锁了,因为是先访问一级缓存的,只要锁上了一级缓存,其他缓存都无法使用
- 从一级缓存中获取
- 一级缓存中没有就从二级缓存中获取
- 二级缓存中没有,从三级缓存获取该bean的ObjectFactory
- 利用ObjectFactory获取bean,并存放二级缓存中进行提前暴露,并且删除三级缓存,因为二级缓存中已经有了,那么三级缓存就没必要了
-
所以,最早暴露Bean的是三级缓存,从三级缓存中获取暴露的bean,是会移去二级缓存中去的
-
最终返回SingleonObject
采用缓存和提前暴露的机制可以解决单例的循环依赖问题,出现循环依赖的时候不会去创建新依赖,而是使用前面正在创建的依赖
原型模式下解决循环依赖
假如单例缓存中没有,即三级缓存并没有提前暴露该bean,那么就要从头进行加载bean了
首先要理解,创建有依赖的bean其实是一个递归过程,我们并不知道此时位于哪一个bean的初始化
所以,在进行从头加载bean时,也要判断单例缓存中有没有,再判断原型模式下是不是出现了循环依赖
具体的源码如下
//原型模式下
//判断这个bean是不是已经在创建了
if (isPrototypeCurrentlyInCreation(beanName)) {
//如果这个bean已经在创建,那就代表出现了循环引用的问题
//直接抛错
throw new BeanCurrentlyInCreationException(beanName);
}
//判断bean是不是存在于上级的工厂中
//先获取上级的工厂
BeanFactory parentBeanFactory = getParentBeanFactory();
//判断上级工厂是否未空,并且IOC容器中是否有定义的BeanDefinition
//一般不会进来这里的
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
//进行类型检查
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
//下面这里才是真正地去保证bean的成员属性bean是已经初始化好的
try {
//判断指定类型是否为空
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
//从IOC容器中去获取bean的配置
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
//获取bean的配置的所有依赖
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
//遍历所有依赖的bean
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//注册bean的依赖
//这一步是提前曝光bean的依赖
registerDependentBean(dep, beanName);
try {
//递归加载此时的依赖bean
//这个方法依然去调用了doGetBean去加载
//加载的时候又会去检测是否出现循环依赖
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
//如果要创建的bean是单例模式的,单例模式创建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
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;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//如果要创建的bean是原型的,原型模式创建
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//其他模式进行创建
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
从代码中可以看到,原型模式下解决循环依赖也是使用提前曝光的方法的
- 判断当前原型bean是否正在创建中
- 如果正在创建中就代表之前提前暴露过了,出现了循环依赖的问题
- 如果没在创建中
- 从容器中取出要创建的beanDefinition
- 遍历该beanDefinition的所有依赖bean
- 将依赖bean进行曝光,表示该bean正在创建
- 递归调用getBean方法进行加载依赖的bean,因为Spring规定,加载bean必须要保证其依赖的bean要加载完,所以采用递归的方式
- 递归去调用getBean方法对所有的依赖进行循环依赖检测
下面就逐步去看一下是怎么实现的
判断当前原型Bean是否正在创建中
从代码上看,对应的代码为isPrototypeCurrentlyInCreation
这个方法的源码如下
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
//从本地的TheadLocal中取出正在创建的bean
//也就是说Spring将正在创建的原型bean存储在ThreadLocal中
//因为单例bean是全局使用的,必须使用同一个集合
//但原型bean是使用一次就创建一次,所以不需要使用全局的集合,只需要ThreadLocal存储就行
//因为哪个线程使用原型bean就这个线程负责创建和销毁即可
Object curVal = this.prototypesCurrentlyInCreation.get();
//如果ThreadLocal中不为空,且ThreadLocal中正在创建的bean包含当前的beanName
//那么就代表当前bean已经在创建了,产生了循环依赖问题
//而且这里看到,假如只有一个原型bean正在创建,那么ThreadLocal只会存储这个原型bean的beanName
//如果有多个进行创建,那么ThreadLocal存储的是一个Set集合,并且Set集合里面存储的是正在创建的beanName
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
从源码上可以知道
- Spring对于原型bean的创建使用了ThreadLocal作为缓存
- 当只有一个bean正在创建时,ThreadLocal仅仅存储一个字符串
- 当有多个bean正在创建时,ThreadLocal存储的是一个Set集合,Set集合里面存的是所有正在创建的beanName
从容器中取出RootBeanDefinitions
先说明一下RootBeanDefinition,RootBeanDefinition其实也是代表一个BeanDefinition,从注释上可以看出这个RootBeanDefinition是针对有继承关系的Bean的,换句话说,其实RootBeanDefinition代表的是父类!!! 如果没有继承关系,才代表是当前类
方法里面的源码如下
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
//先从mergedBeanDefinitions中取出RootBeanDefinition
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
//如果容器中有且该RootBeanDefinition不允许进行re-merged操作
//re-merged操作其实就是合并父类,因为RootBeanDefinition代表的是父类
//但我们初始化的时候,先初始化的是子类,所以需要进行将父类合并进来
if (mbd != null && !mbd.stale) {
//直接返回容器中的bean
return mbd;
}
//如果容器中没有,或者容器中的RootBeanDefinition允许进行合并
//那就需要进行合并操作,并且返回合并后的RootBeanDefinition
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
从代码上可以看到
-
RootBeanDefinitions代表的是父类,并且是通过合并子类的方式类进行创建的
-
Spring使用了mergedBeanDefinitions容器,为一个初始化容量为256的ConcurrentHashMap来存储RootBeanDefinition
-
RootBeanDefinition通过一个stale变量来控制该bean是否还可以继续合并
-
如果容器中没有、或者容器中有,但该RootBeanDefinition还允许继续进行合并,那就需要先进行合并,再将合并后的RootBeanDefinition返回
-
并且合并的bean的配置从IOC容器中去取,得到IOC容器里面的BeanDefinition
合并RootBeanDefinition
可以看到,其调用了重载的方法,并且调用了
源码如下
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
//先对mergedBeanDefinitions容器进行上锁
//避免在进行合并的时候,有人在使用mergedBeanDefinitions
//因为合并后是要进行更新替换的,假如多个线程进来都合并这个bean就会产生并发问题
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
// 如果containningBd为空,就代表没有要内嵌的bean
//并且可以看到,这个参数传进来就是为Null的,证明加载bean的时候是没有管内嵌bean的
if (containingBd == null) {
//从mergedBeanDefinitions取出旧的RootBeanDefinition
mbd = this.mergedBeanDefinitions.get(beanName);
}
//如果没有,或者允许进行合并
//旧可以进行下面的合并操作了
if (mbd == null || mbd.stale) {
//使用previous去承载旧的RootBeanDefinition
previous = mbd;
//如果要合并的beanDefinition,并没有父类,就是没有Parent
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
// 那就进行复制即可,不需要进行合并了
if (bd instanceof RootBeanDefinition) {
//如果IOC容器里面的BeanDefinition本来就是RootBeanDefinition类型
//进行拷贝,并且这里是是一个浅拷贝
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
//如果不是RootBeanDefinition类型的
else {
//使用构造函数去构造RootBeanDefinition
mbd = new RootBeanDefinition(bd);
}
}
//如果要合并的beanDefinition,是有parent的
//那就代表这个beanDefinition是一个ChildBeanDefinition
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
//同理,去将parentName转化为对应的beanName,因为可能出现别名什么的
//签名已经看过这个方法底层了,就不再进行赘述了
String parentBeanName = transformedBeanName(bd.getParentName());
//如果要合并的beanName与parentBeanName不相等
//那就证明需要进行合并
if (!beanName.equals(parentBeanName)) {
//可以看到这里递归地去进行合并了
pbd = getMergedBeanDefinition(parentBeanName);
}
//如果是相等的name
else {
//只能使用父类的BeanFactory来进行实例化父类了
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);
}
// Deep copy with overridden values.
//pbd是经过递归返回的结果,为是最上层的父类
//并且进行深拷贝得到最上层的父类
mbd = new RootBeanDefinition(pbd);
//bd此时是子类的beanDefinition
//父类要装上子类的一些属性,所以要进行重写
//父类mbd从子类bd重写一些属性
//其实从这里就可以知道Spring是怎么处理具有继承关系的bean了
//通过合并重写的方式去创建有继承关系的bean
//通过递归的方式得到父Bean,然后得到的父Bean重写当前子Bean的一些属性
//重写子类Bean的属性相当于就是合并了子类Bean
//此时RootBeanDefinition就变为了mbd,合并了子类的属性
mbd.overrideFrom(bd);
}
// 给RootBeanDefinition设置范围,默认为单例
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
//如果RootBeanDefiniton的范围为单例,并不一定为单例
//RootBeanDefinition的范围还会受限于containningBd,也就是内嵌的bean
//假如内嵌的containningBd不是单例,但RootBeanDefinition是单例
//那么就会RootBeanDefinition的范围以containningBd为准
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
//将RootBeanDefinition的范围设置为containingBd的范围
mbd.setScope(containingBd.getScope());
}
//并且如果没有内嵌bean会进行缓存!!!
//存入mergedBeanDefinitions容器中
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
//
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
//返回创建好的RootBeanDefinition
return mbd;
}
}
总结一下合并RootBeanDefinition的流程
- 对mergedBeanDefinitions进行上锁(ConcurrentHashMap进行上锁)
- 从mergedBeanDefinition中去获取旧的RootBeanDefinition
- 判断旧的RootBeanDefinition是否为空和是否允许合并
- 从BeanDefinition去获取parentName,并且转化为parentBeanName
- 如果当前的beanName与parentBeanName不一致,那就代表正常的继承关系
- 递归去构建parentBeanName的RootBeanDefinition(重要)
- 如果当前的beanName与parentBeanName一致
- 那就只能通过parent的BeanFactory去进行创建了
- 递归得到RootBeanDefinition后,进行一份深拷贝(因为要替换mergedBeanDefinition里面的元素)
- 并且RootBeanDefinition要重写子类的属性
- 判断新创建的RootBeanDefinition是否有范围
- 如果没有范围,默认设置为单例
- RootBeanDefinition范围还会受限于ContainningBd
- 如果内嵌Bean有自己的范围并且不是单例,而RootBeanDefinition是单例
- RootBeanDefinition的范围会改成containningBd的范围
- 不过在加载的时候,containningBd一般都为Null
- 最终将新创建的RootBeanDefinition放入mergedBeanDefinitions容器中进行更新,并且返回新创建的RootBeanDefinition
加载依赖bean
获取了RootBeanDefinition之后,下一步就是去假爱依赖的bean了
对应的代码为这一块
//获取RootBeanDefinitions的依赖
String[] dependsOn = mbd.getDependsOn();
//如果有依赖要注入的bean
if (dependsOn != null) {
//遍历所有的依赖bean
for (String dep : dependsOn) {
//判端当前依赖的bean和RootBeanDefinition是否出现循环依赖
if (isDependent(beanName, dep)) {
//如果出现就会抛出异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//没有出现循环依赖就进行注册依赖的bean
//这里注册是指注册这个依赖的bean进beanName里面
//代表beanName指定的bean已经要依赖这个dep了
//相当于提前暴露
registerDependentBean(dep, beanName);
try {
//递归去加载依赖的bean
//同理依赖的bean自身也会检查自己有没有出现循环依赖问题
getBean(dep);
}catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
获取RootBeanDefinitions的依赖
可以看到,这是个位于AbstractBeanDefinition的字符数组
这个数组肯定在前面的合并操作中不停变化的,因为合并操作是一个递归过程,并且每次递归都产生新的RootBeanDefinition
判断当前依赖的bean是否产生重复依赖
可以看到这里首先给dependentBeanMap进行了上锁
并且这个dependentBeanMap是一个容量为64的ConcurrentHashMap,并且里面的键值对形式为<String,Set>,key代表beanName,而set集合里面代表该beanName的beanDefinition需要依赖到的bean,并且这是一个LinkedHashSet,后面会提到,所以可以知道这个dependentBeanMap的作用其实就是保存bean和其依赖bean的关系
上锁了之后会调用isDepend的重载方法
源码如下
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
//alreadySeen是用来存储已经检查的依赖
//也是检查循环依赖的关键,因为是用alreadySeen进行存储当前依赖到bean的所有依赖
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
//转化beanName
String canonicalName = canonicalName(beanName);
//取出dependentBeanMap中该beanName对应的依赖bean的set集合
//针对不同依赖bean之间是否出现循环依赖
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
//如果set集合没有,代表该bean没有依赖bean
if (dependentBeans == null) {
//返回false
//代表beanName与dependentBeanName没有冲突
return false;
}
//如果依赖bean集合存在,并且里面已经有依赖这个dependentBeanName了
if (dependentBeans.contains(dependentBeanName)) {
//代表已经依赖过了,并且出现了重复依赖
//注意这里只是重复依赖,并不是循环依赖
return true;
}
//如果依赖bean集合存在,且里面没有依赖这个dependentBeanName
//那么就需要判断其他依赖的bean中有没有依赖这个dependentBeanName
//遍历所有依赖bean
for (String transitiveDependency : dependentBeans) {
//alreadySeen用来存储已经检查过的依赖bean
//第一次进来会为空,因为之前并没有检查
//需要进行初始化
if (alreadySeen == null) {
//可以看到alreadySeen是一个HashSet
alreadySeen = new HashSet<>();
}
//将检查完的bean添加进alreadySeen中去
alreadySeen.add(beanName);
//递归去检查依赖bean中是不是有依赖dependentBeanName
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
//存在重复依赖,返回true
return true;
}
}
return false;
}
从代码中可以看到
-
Spring使用一个临时的HashSet存储所有该依赖bean(传进来的dependentBeanName)的依赖bean
-
通过HashSet去进行判断是否出现了重复依赖和循环依赖
- 重复依赖是指:依赖了A bean 但依赖的另一个B Bean却又依赖了A Bean
- 循环依赖是指:依赖A bean,但A bean又依赖了自己
-
通过递归的方式,将当前依赖bean的所有依赖,包括依赖的依赖都存储进alreadySeen的set集合中,每次都会判断set集合中是否已经有该依赖了,alreaySeen只是一个临时集合,就是检查当前依赖bean自身使用到的,如果当前依赖bean自身没问题,需要去判断其他同级的依赖bean是否与其有冲突,也就需要一个全局记录依赖bean的容器,说白了就是dependentBeanMap
-
并且这里要注意,这里仅仅只是判断当前依赖的bean是否产生重复依赖和循环依赖,在前面看到源代码是循环判断所有依赖的bean的
-
也就是说这里仅仅检查当前依赖的bean的本身是否出现重复依赖
注册依赖bean
经过上面已经将检测完当前该依赖bean是否有产生循环依赖了,如果没有产生,那就需要进行注册依赖bean了,要记得对于依赖bean的操作是一个循环操控所有的依赖bean,前面判断当前依赖的bean是否产生循环依赖,仅仅只是当前依赖的bean,那么对于后面依赖的bean又有没有对之前的bean进行重复依赖呢?比如bean A里面有bean B,但与bean A属于同一级别的Bean C里面又有bean B,所以就需要一个注册的功能,使用一个容器去存储已经检查过的依赖bean,也就是上面提到的dependentBeanMap
对应的方法是registerDependentBean
源码如下
public void registerDependentBean(String beanName, String dependentBeanName) {
//获取真正的beanName,因为有可能是别名形式
String canonicalName = canonicalName(beanName);
//对dependentBeanMap上锁
//前面判断循环依赖也会对dependBeanMap上锁,这里也会进行上锁
synchronized (this.dependentBeanMap) {
//根据beanName去获取该bean的此时的所有依赖bean
//是一个set集合,并且从这里可以看到,是一个LinkedHashSet
Set<String> dependentBeans =
this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
//往依赖bean的set集合里面去添加所有的
//如果已经注册过直接return
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}
//如果没有注册过,注册了进去之后会进行下一个操作
//给dependenciesForBeanMap进行上锁
//这个dependenciesForBeanMap其实跟dependentBeanMap有点相反
//dependenciesForBeanMap存储的是依赖bean与其所有依赖该bean的bean的映射关系
//而dependentBeanMap存储的是bean与其所有依赖bean的关系
//相当于是互换的概念,因为bean与依赖bean是多对多的关系
synchronized (this.dependenciesForBeanMap) {
//根据依赖bean的beanName去获取所有依赖该bean的bean集合
//可以看到,也是一个LinkedHashSet
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
//添加
dependenciesForBean.add(canonicalName);
}
}
从代码上可以看到,注册依赖beam是要去更新两个容器的
- dependsBeanMap:bean与所有依赖bean的关系
- dependenciesForBeanMap:依赖bean与所有依赖该bean的bean的关系