文章目录
前言
前面几篇文章中,我们梳理了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.抽象接口BeanDefinitionRegistry
Spring首先定义了BeanDefinitionRegistry,提供了读写的方法。这个基本上和我们的想法是
代码如下:
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* Register a new bean definition with this registry.
* Must support RootBeanDefinition and ChildBeanDefinition.
* @param beanName the name of the bean instance to register
* @param beanDefinition definition of the bean instance to register
* @throws BeanDefinitionStoreException if the BeanDefinition is invalid
* @throws BeanDefinitionOverrideException if there is already a BeanDefinition
* for the specified bean name and we are not allowed to override it
* @see GenericBeanDefinition
* @see RootBeanDefinition
* @see ChildBeanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/**
* Remove the BeanDefinition for the given name.
* @param beanName the name of the bean instance to register
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* Return the BeanDefinition for the given bean name.
* @param beanName name of the bean to find a definition for
* @return the BeanDefinition for the given name (never {@code null})
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* Check if this registry contains a bean definition with the given name.
* @param beanName the name of the bean to look for
* @return if this registry contains a bean definition with the given name
*/
boolean containsBeanDefinition(String beanName);
/**
* Return the names of all beans defined in this registry.
* @return the names of all beans defined in this registry,
* or an empty array if none defined
*/
String[] getBeanDefinitionNames();
/**
* Return the number of beans defined in the registry.
* @return the number of beans defined in the registry
*/
int getBeanDefinitionCount();
/**
* Determine whether the given bean name is already in use within this registry,
* i.e. whether there is a local bean or alias registered under this name.
* @param beanName the name to check
* @return whether the given bean name is already in use
*/
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的注册思路和实现过程。如果对你有所帮助,请让我知道,感谢你的阅读。