「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」
书接上文,这里就到了比较复杂的构造bean这一部分了,回顾一下之前的部分:
自己创建
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//这一步会检查一下是不是抽象的BD,是的话就直接报错了,因为根据之前的描述我们也知道抽象的BD是不能构造成bean的。
checkMergedBeanDefinition(mbd, beanName, args);
获取到了BD,接下来要正式走创建bean的流程了。
第一步:保证依赖的bean都创建了
这里对应的代码如下:
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
//这里又进行递归了
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
这里的依赖,指的是受@DependsOn()注释的相关类,并不指类中定义的属性。
-
注意一下这里报错的内容:Circular depends-on,也就是说@DependsOn不能是互相依赖的。
-
那么这里就会有另一个问题:如果发生了三角循环的相互依赖,那么不能直接判断,还需要看一看是不是有循环依赖的关系,因此
isDependent(beanName, dep)这个方法里就会做这个判断,循环地来看看是否依赖的链表节点上存在循环依赖的问题。这里就得有记录,这个记录点在这里:
registerDependentBean(dep, beanName);这里会把依赖的相关信息,存在一个map里面。
-
要注意:这里的循环依赖问题,指的是@DependsOn的依赖,而不是@Autowired的那个依赖,也就是说这里的dependsOn的优先级要比@Autowired高,这里的@DependsOn指的是必须初始化咯。
在记录之后,就会去创建依赖的bean:getBean(dep);
第二步:区分作用域(scope)
回忆一下,创建bean有几步?
- 类加载,实例化,前后process,属性注入
而bean又分为:原型bean和单例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); } -
原型:
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); } -
其他scope(SpringMVC里的,比如request,session等):
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); } }这里的scope其实和单例意思差不多,只是缓存的信息会存在scope里,对应的scope里的这些bean也都是单例的,只是单例的是全局的这里是scope的。
这里关键代码都差不多:
//原型bean、其他scope记录下现在在创建,用map来存
beforePrototypeCreation(beanName);
createBean(beanName, mbd, args);
//原型bean、其他scope记录下现在创建好了,也是用map来存
afterPrototypeCreation(beanName);
getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
区别就是,原型的话就直接创建,单例会尝试获取。
这里关键就在createBean上:创建bean对象。