glmapper

Spring源码系列:BeanDefinition载入(下)

字数统计: 862阅读时长: 3 min
2018/11/10 Share

Spring源码系列:BeanDefinition载入(上)中已经大概捋了一下解析过程,本篇将记录一下bean的注册过程。


bean的注册就是DefaultListableBeanFactory中registerBeanDefinition方法来完成的。那我就来看registerBeanDefinition这个方法的具体逻辑。


1、beanDefinition类型判断和验证


这里的验证主要是验证不能将静态工厂方法与方法重写相结合(静态工厂方法必须创建实例);


if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(),
beanName,“Validation of bean definition failed”, ex);
}
}

2、尝试从beanDefinitionMap中获取老的bean


这里就是先根据beanName从beanDefinitionMap去取BeanDefinition,并将结果给oldBeanDefinition。


BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);

3、beanDefinitionMap中已经存在名为beanName的Beandefinition


如果当前beanDefinitionMap中已经存在名为beanName的Beandefinition了(即检查是否有相同名称的beanDefinition已经在Ioc容器中注册过了)。,如果有,则进行以下具体策略:



  • 如果不允许bean被覆盖,则直接抛出不能重新注册,bean已经存在这样的异常信息

  • 使用框架生成的Bean来代替用户自定义的bean

  • 覆盖原有的Beandefinition


if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
//省略异常代码
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
//省略异常代码
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
//提示覆盖log信息
}
else {
//提示覆盖log信息
}
//覆盖原有的Beandefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}

4、beanDefinitionMap不存在名为beanName的Beandefinition


//检查bean的创建阶段是否已经开始,也就是说是否已经创建了
if (hasBeanCreationStarted()) {
//Cannot modify startup-time collection elements anymore (for stable iteration)
// 无法修改启动时间收集元素(用于稳定迭代)(译注)
//注册过程需要保证数据的一致性,所有需要加锁同步
synchronized (this.beanDefinitionMap) {
//注册到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
//下面就是将当前beanName存放到beanDefinitionNames中
List<String> updatedDefinitions = new ArrayList<String>(
this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
//如果单例模式的bean名单中有该bean的name,那么移除掉它。
//也就是说着,将一个原本是单例模式的bean重新注册成一个普通的bean
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new
LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
// 仍处于启动阶段,bean还没有开始注册
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;

5、执行缓存清除



  • 1:oldBeanDefinition如果存在,且执行到了这里也没有抛出异常,说明该BeanDefinition已经被覆盖,缓存需要更新。


  • 2:如果是单例模式的bean对象则Set中包含该beanName,执行到这里说明该BeanDefinition已经从一个单例模式的bean变为了一个普通的bean,所以缓存也需要更新。



if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}

OK,我们来看下resetBeanDefinition这个方法:


这个方法的作用就是重置给定bean的所有bean定义缓存,包括从它派生的bean的缓存。


protected void resetBeanDefinition(String beanName) {
// 如果已经创建,则删除给定bean的合并bean定义。
clearMergedBeanDefinition(beanName);

// 如果有的话,从singleton 高速缓存中删除相应的bean。
//但是这也不是必须的,而只是为了覆盖上下文的默认bean
//(就是从manualSingletonNames中移除)
destroySingleton(beanName);
//递归的方式来 重置具有给定bean作为父项的所有bean定义。
for (String bdName : this.beanDefinitionNames) {
if (!beanName.equals(bdName)) {
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
if (beanName.equals(bd.getParentName())) {
resetBeanDefinition(bdName);
}
}
}
}

Bean的注册就到这里了,下一篇学习的是DefaultListableBeanFactory这个集大成者容器。

原文作者:GuoLei Song

原文链接:http://www.glmapper.com/2018/11/10/spring-series-bd-loaded-3/

发表日期:November 10th 2018, 2:08:17 pm

更新日期:December 14th 2019, 10:54:37 am

版权声明:转载请注明出处

CATALOG