Spring: BeanDefinition的注册(源码跟进)

 

前言:

在这之前Spring已经通过document对象解析出BeanDefinition实例

以下就是将BeanDefinition注册进容器的步骤

 

DefaultBeanDefinitionDocumentReader 类中的 processBeanDefinition()方法完成了对BeanDefinition的注册

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  //BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类
  //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//向SpringIOC容器注册解析得到的BeanDefinition,这是BeanDefinition向IOC容器注册的入口
      //传递的参数bdHolder为BeanDefinition的包装类,另一个参数为registry实例。

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
//在完成BeanDefinition注册之后,往容器发送注册完成的事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

方法中的Registry参数在跟进参数后可以发现返回的是AbstractBeanDefinitionReader中的Registry变量,该Registry变量便是BeanDefinitionRegistry的实例。

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

this.registry = registry;

// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}

// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}

随后我们查看AbstractBeanDefinitionReader构造函数发现Registry变量是通过构造函数的参数传递的

 

并且在构造函数中的IF函数中判断了传递过来的Registry是否为ResourceLoader实例,如果是则把Registry强转ResourceLoader并且传递到成员变量(resourceLoader)上。如果不是则给成员变量(resourceLoader)传递新的PathMatchingResourcePatternResolver对象。

 

 

PathMatchingResourcePatternResolver:支持多配置文件的资源加载器

 

 

 

 

其中的 BeanDefinitionReaderUtils 调用了 registerBeanDefinition() 方法来将我们的 BeanDefinition 注册到 DefaultListableBeanFactory 中的 beanDefinitionMap 中。

接下来我们进入 registerBeanDefinition() 方法。

public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {

String beanName = definitionHolder.getBeanName();//获取Bean的名字
// 将BeanDefinition及其名字注册到容器里
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

//如果存在别名则逐个注册进容器
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

 

我们可以通过Debug的方式跟进到该方法,此时我们会发现

registry参数是自身(DefaultListableBeanFactory)传递过来

的,前面我们说到DefaultListableBeanFactory类实现了

BeanDefinitionRegistry接口,然后在现在这个方法中将自己

当作Registry使用。也就是比较经典的委派模式

 


 

 

 


public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {

Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");

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

BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
   //检查是否有同名的BeanDefinition已经在IOC容器中注册 
if (existingDefinition != null || containsSingleton(beanName)) {
    //尝试重置所有已经注册过的BeanDefinition的缓存,包括BeanDefinition
    //的父类以及合并的BeanDefinition的缓存,所谓的合并BeanDefinition
    //指的是有parent属性的BeanDefinition,该BeanDefinition会把parent的
    //BeanDefinition属性合并在一块

resetBeanDefinition(beanName);
}
}

 

 

随后我们跟进registerBeanDefinition方法。方法中首先会进行校验,然后会从容器中获取BeanDefinition实例,看看是否存在。

 

1.如果实例已经注册过了便会根据容器的配置来决定是否是否支持覆盖原先的实例,随后对权限等等进行校验,如果最后都通过了则最终更新beanDefinitionMap

 

2.如果实例没有注册过,则进入else代码块中:首先判断容器是否已经开始创建Bean实例

2.1如果注册表已经注册过了,随后用synchronized锁住beanDefinitionMap,此时Map中已经存有Bean实例了,在此对它进行新增添加,后更新注册表中的beanDefinitionNams(将新增的和原先的添加进去)。

2.2如果注册表是第一次注册,则将Bean直接注册进入后

 

最后removeManualSingletonName(beanName)再对已经注册的单例Bean名字列表进行更新。

 

注册完后会执行最后一行代码 this.frozenBeanDefinitionNames = null;这行代码会将注册期间被冻结的BeanDefinition的名字列表清除掉  


 

removeManualSingletonName()方法中只调用了方法updateManualSingletonNames

在方法中首先判断是否有bean创建好了

  如果是第一次创建:直接定义上bean。

  如果不是第一次创建:给注册表加上synchronized锁,从单例表中移除bean后重新定义bean。

 

 1 private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
 2         if (hasBeanCreationStarted()) {
 3             // Cannot modify startup-time collection elements anymore (for stable iteration)
 4             synchronized (this.beanDefinitionMap) {
 5                 if (condition.test(this.manualSingletonNames)) {
 6                     Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
 7                     action.accept(updatedSingletons);
 8                     this.manualSingletonNames = updatedSingletons;
 9                 }
10             }
11         }
12         else {
13             // Still in startup registration phase
14             if (condition.test(this.manualSingletonNames)) {
15                 action.accept(this.manualSingletonNames);
16             }
17         }
18     }

 

 
 
posted @ 2021-02-17 19:36  _kerry  阅读(241)  评论(0编辑  收藏  举报