1.0 registerBeanDefinition
对于配置文件,解析也解析完了,装饰也装饰完了,对于得到的BeanDefinition已经可以满足后续的使用了,唯一剩下的工作就是注册了,
也就是: processBeanDefinition 方法中的
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());
代码如下:
1 /**
2 * Process the given bean element, parsing the bean definition and registering it with
3 * the registry.
4 */
5 protected void processBeanDefinition(Element ele,
6 BeanDefinitionParserDelegate delegate) {
7 // 委托BeanDefinition类的parseBeanDefinitionElement方法进行元素解析,返回Beandefinition
8 // 类型的实例bdHolder 经过这个方法之后,
9 // bdHolder实例已经包含了我们配置文件中的各种属性了,例如 : class,name,id,alias
10 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
11 if (bdHolder != null) {
12 //当返回的bdHolder 不为空的情况下,若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析.
13 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
14 try {
15 // Register the final decorated instance.
16 // 解析完成之后,需要对解析后的bdHolder 进行注册,同样注册操作委托给了BeanDefinitionUtils 的 registerBeanDefinition
17 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,
18 getReaderContext().getRegistry());
19 }
20 catch (BeanDefinitionStoreException ex) {
21 getReaderContext().error(
22 "Failed to register bean definition with name '"
23 + bdHolder.getBeanName() + "'", ele, ex);
24 }
25 // Send registration event.
26 // 最后发出响应事件,通知相关的监听器,这个bean已经加载完了.
27 getReaderContext().fireComponentRegistered(
28 new BeanComponentDefinition(bdHolder));
29 }
30 }
我们继续追踪下去:
1 /**
2 * Register the given bean definition with the given bean factory.
3 *
4 * @param definitionHolder the bean definition including name and aliases
5 * @param registry the bean factory to register with
6 * @throws BeanDefinitionStoreException if registration failed
7 */
8 public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder,
9 BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
10
11 // Register bean definition under primary name.
12 // 使用 beanName 作为唯一标示注册
13 String beanName = definitionHolder.getBeanName();
14 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
15 // 注册所有别名
16 // Register aliases for bean name, if any.
17 String[] aliases = definitionHolder.getAliases();
18 if (aliases != null) {
19 for (String aliase : aliases) {
20 registry.registerAlias(beanName, aliase);
21 }
22 }
23 }
从上面代码可以看出,解析的BeanDefinition都会被注册到BeanDefinitionRegister 类型的实例 register 中,而对于beanDefinition 的注册分为2部分,
1. 通过beanName 注册
2. 通过别名注册;
2.0 通过beanName 注册
对于使用beanDefinition的注册,或许很多人都认为是将BeanDefinition 直接放入map中就好了,使用beanName作为Key ,实际上,的确Spring的确是这么做了,只不过除此之外,它还做了点别的事情,
我们来看看代码:
1 @Override
2 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
3 throws BeanDefinitionStoreException {
4
5 Assert.hasText(beanName, "Bean name must not be empty");
6 Assert.notNull(beanDefinition, "BeanDefinition must not be null");
7
8 if (beanDefinition instanceof AbstractBeanDefinition) {
9 try {/*
10 * 注册前最后一次效验,这里的效验不同之前的XML文件效验,主要是对于AbstractBeanDefinition
11 * 属性中的methodOverrides 效验; 效验methodOverrides 是否与工厂方法并存或者methodOverrides
12 * 对应的方法根本不存在
13 */
14 ((AbstractBeanDefinition) beanDefinition).validate();
15 }
16 catch (BeanDefinitionValidationException ex) {
17 throw new BeanDefinitionStoreException(
18 beanDefinition.getResourceDescription(), beanName,
19 "Validation of bean definition failed", ex);
20 }
21 }
22 // 应为beanDefinitionMap 是全局变量,这里定会存在并发
23 synchronized (this.beanDefinitionMap) {
24 // 处理注册已经注册的beanName情况
25 BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
26 if (oldBeanDefinition != null) {
27 // 如果对应beanName已经注册 并且在配置文件中配置了beanName不能被覆盖,则抛出异常
28 if (!this.allowBeanDefinitionOverriding) {
29 throw new BeanDefinitionStoreException(
30 beanDefinition.getResourceDescription(), beanName,
31 "Cannot register bean definition [" + beanDefinition
32 + "] for bean '" + beanName + "': There is already ["
33 + oldBeanDefinition + "] bound.");
34 }
35 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
36 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or
37 // ROLE_INFRASTRUCTURE
38 if (this.logger.isWarnEnabled()) {
39 this.logger.warn("Overriding user-defined bean definition for bean '"
40 + beanName
41 + " with a framework-generated bean definition ': replacing ["
42 + oldBeanDefinition + "] with [" + beanDefinition + "]");
43 }
44 }
45 else {
46 if (this.logger.isInfoEnabled()) {
47 this.logger.info("Overriding bean definition for bean '"
48 + beanName + "': replacing [" + oldBeanDefinition
49 + "] with [" + beanDefinition + "]");
50 }
51 }
52 }
53 else {
54 // 记录beanName
55 this.beanDefinitionNames.add(beanName);
56 this.frozenBeanDefinitionNames = null;
57 }
58 // 注册beanDefinition
59 this.beanDefinitionMap.put(beanName, beanDefinition);
60 }
61 // 重置所有beanName 对应的缓存(清楚之前对应beanName 的缓存)
62 resetBeanDefinition(beanName);
63 }
上面代码中,我们看到对于bean在处理方式上主要做了几个步骤,
1. 注册前最后一次效验,这里的效验不同之前的XML文件效验,对于AbstractBeanDefinition属性中的methodOverrides 效验; 效验methodOverrides 是否与工厂方法并存或者methodOverrides
2. 如果对应beanName已经注册 并且在配置文件中配置了beanName不能被覆盖,则抛出异常 3. 加入map缓存
4.清除解析之前对应beanName 的缓存
2. 通过别名注册BeanDefinition
在理解注册beanName的原理后,理解别名注册就容易多了;
代码如下:
SimpleAliasRegistry.java
1 @Override
2 public void registerAlias(String name, String alias) {
3 Assert.hasText(name, "'name' must not be empty");
4 Assert.hasText(alias, "'alias' must not be empty");
5 // 如果beanName与alias 相同的话,不记录alias ,并删除对应的alias
6 if (alias.equals(name)) {
7 this.aliasMap.remove(alias);
8 }
9 else {
10 // 如果alias 不允许被覆盖则抛出异常
11 if (!allowAliasOverriding()) {
12 String registeredName = this.aliasMap.get(alias);
13 if (registeredName != null && !registeredName.equals(name)) {
14 throw new IllegalStateException("Cannot register alias '" + alias
15 + "' for name '" + name
16 + "': It is already registered for name '" + registeredName
17 + "'.");
18 }
19 }
20 // alias 循环检查, 当 A -> B 存在时, A->C->B 的时候则会抛出异常
21 checkForAliasCircle(name, alias);
22 // 注册alias
23 this.aliasMap.put(alias, name);
24 }
25 }
经过一番波折, 最后通过getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));发出响应事件,通知相关的监听器,这个bean已经加载完了. 这里的实现只为了扩展,当程序开发员需要对注册BeanDefinition事件进行监听的时候可以通过注册监听器的方式将处理逻辑写入监听器中,目前,Spring 并没有对此事件做任何逻辑处理.