- 前言
- 一、管理的必要性
- 框架设计
- 工程实现
- 二、Spring的实现
- 1.抽象接口BeanDefinitionRegistry
- 2. 具体实现DefaultListableBeanFactory
- 三、特色方法
- removeBeanDefinition
- BeanDefinitionOverriding
- 总结
前言
前面几篇文章中,我们梳理了BeanDefinition相关的Resource、Resource加载、基于XML文件的BeanDefinition不同颗粒度解析,和XML中自定义标签解析。接下来,看看BeanDefinition的注册。
在开始之前,先回顾下BeanDefinition。BeanDefinition是Bean的相关定义。对一个具体的BeanDefinition,对内包含BeanDefinition对应的class,scope,init-method,destory-method等等,对外包含对其他BeanDefinition的关联关系,包括依赖和继承。
到这里,咱们讨论的是单个BeanDefinition。实际工程中,Bean有多个,对应的BeanDefinition也不止一个。于是灵魂拷问来了,要不要管理,如何管理?
所以,本文先YY下BeanDefinition管理的必要性,再看BeanFactory是怎么管理的,最后仔细看下Spring作者在操刀时加入的个人思想。
一、管理的必要性 框架设计
BeanDefinition对象是一类关键对象。主要体现在依赖关系复杂。依赖关系包括非BeanDefinition对BeanDefinition的依赖,以及BeanDefinition之间的依赖,就像中年人上有老,下有小同时还得照顾亲戚。依赖关系复杂,直接体现就是对象构造过程比较曲折,简单说不能 new XXBeanDefinition() 就完事了。
工程实现由于存在依赖,也需要快速寻找依赖,很自然就想到通过集合集中管理,比如使用Map集合。Spring中也确实是这么干的。于是就需要一个Map集合+写入/获取方法。于是就YY出来了一个BeanDefinitionFactory(实际上是不存在的)接口,提供一个写入和获取方法。具体实现类内部通过Map集合实现读写。
二、Spring的实现 1.抽象接口BeanDefinitionRegistrySpring首先定义了BeanDefinitionRegistry,提供了读写的方法。这个基本上和我们的想法是
代码如下:
public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}
2. 具体实现DefaultListableBeanFactory
代码如下(示例):
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 省略
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 省略
}
到这里,基本上和前面的预期差不多,但是如果仔细看源码,其中的复杂程度远超想象。本文中,我们先关注BeanDefinition注册过程,忽略其他代码。
三、特色方法 removeBeanDefinition
既然都集合管理了,那么增删改查这套应该给整齐了。但具体什么时候会使用删除,后面的文章中我们再讨论。Spring中许多代码在写的时候,方法都是完整的,哪怕暂时用不到可以先留空。至少从逻辑上看,相关操作都是完整的。
BeanDefinitionOverriding终点关注这个overriding,就意味着可以覆盖。既然可以覆盖总得有一些条件吧。咱们仔细看下源码。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 省略校验代码
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 {
// 容器已启动的特殊处理暂时忽略
}
}
从代码中可以看到:
- 对于重名的BeanDefinition,如果不允许overriding直接异常;
- 如果允许overriding,先比较角色。这个角色在Spring中定义了3种,级别从低到高分别是ROLE_APPLICATION(用户定义Bean), ROLE_SUPPORT(Spring内部使用,可能跟用户有关), ROLE_INFRASTRUCTURE(Spring内部使用,和框架使用者完全无关)。越大优先级越高。高优先级可以覆盖低优先级的BeanDefinition。
- 如果允许overriding, 并且两个BeanDefinition不相等直接覆盖;
- 关于容器已启动时的特殊处理,后续文章再做讨论。
以上就是今天要讲的内容,本文梳理了Spring中BeanDefinition的注册思路和实现过程。如果对你有所帮助,请让我知道,感谢你的阅读。



