5、spring中Beanefinition完全解析
5、spring中Beanefinition完全解析
大家用过 spring 的应该都知道 BeanDefinition 是记录 bean 的定义信息的,但是我们看源码时会发现,源码中通过 BeanDefinition 接口派生出来好多类,比如 GenericBeanDefinition,AnnotatedGenericBeanDefinition,RootBeanDefinition 等等,那么他们之间有什么区别,都是在什么情况下用到的呢?这篇文章就带大家一起探讨。
1,BeanDefinition 常用类关系图
![ ][nbsp]
2,BeanDefinition 接口
BeanDefinition 是一个接口,定义了修改和获取 Bean 属性值和元数据信息。在 DefaultListableBeanFactory 中定义了 BeanDefinitionMap 来记录解析的 BeanDefinition,定义了 beanDefinitionNames 来记录 BeanDefinition 名字列表:
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
3,AbstractBeanDefinition
new AbstractBeanDefinition() {
@Override
public void setParentName(String parentName) {
}
@Override
public String getParentName() {
return null;
}
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return null;
}
};
AbstractBeanDefinition 是 BeanDefinition 接口的抽象实现,除了 BeanDefinition 中的以上三个方法没实现,其余的全部实现了。
4,GenericBeanDefinition
GenericBeanDefinition 类是 AbstractBeanDefinition 类的具体实现,义为通用的 BeanDefinition。
一般我们通过 xml 定义的普通 bean 在源码中会被解析为 GenericBeanDefinition。
如下 xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="a" class="com.mashibing.A"></bean>
</beans>
调试信息
![ ][nbsp 1]
5,RootBeanDefinition
RootBeanDefinition 也是 AbstractBeanDefinition 的其中一个实现类,它可以单独作为一个 BeanDefinition,也可以作为其他 BeanDefinition 的父类。RootBeanDefinition 在 AbstractBeanDefinition 的基础上定义了更多属性。
在 spring 源码的 refresh 方法中的 invokeBeanFactoryPostProcessors(beanFactory)去执行所有的 BeanFactoryPostProcessor 时会通过去遍历 beanDefinitionNames 集合,然后把 beanDefinitionMap 中的 BeanDefinition 全部合并为 RootBeanDefinition,并且缓存到 mergedBeanDefinitions 中,这样在实例化 bean 时,通过 getMergedLocalBeanDefinition 直接从 mergedBeanDefinitions 中取出来即可。
/** Map from bean name to merged RootBeanDefinition. */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
![ ][nbsp 2]
![ ][nbsp 3]
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
// 用于存储bd的MergedBeanDefinition
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
// 检查beanName对应的MergedBeanDefinition是否存在于缓存中
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
// 如果缓存中没有
if (mbd == null || mbd.stale) {
previous = mbd;
// 如果bd的parentName为空,代表bd没有父定义,无需与父定义进行合并操作
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
// 如果bd的类型为RootBeanDefinition,则bd的MergedBeanDefinition就是bd本身,则直接克隆一个副本
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
// 否则,将bd作为参数,构建一个RootBeanDefinition。
// 正常使用下,BeanDefinition在被加载后是GenericBeanDefinition或ScannedGenericBeanDefinition
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
// bd存在父定义,需要与父定义合并
BeanDefinition pbd;
try {
// 获取父bean的名称,并进行转换
String parentBeanName = transformedBeanName(bd.getParentName());
// 如果当前beanName和父beanName不相同,那么递归调用合并方法
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
// 如果父定义的beanName与bd的beanName相同,则拿到父BeanFactory,
// 只有在存在父BeanFactory的情况下,才允许父定义beanName与自己相同,否则就是将自己设置为父定义
else {
BeanFactory parent = getParentBeanFactory();
// 如果父BeanFactory是ConfigurableBeanFactory,则通过父BeanFactory获取父定义的MergedBeanDefinition
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
// 如果父BeanFactory不是ConfigurableBeanFactory,则抛异常
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve p标注 @Bean 注解的类会使用构造方法自动装配
arent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
// 使用父定义pbd构建一个新的RootBeanDefinition对象
mbd = new RootBeanDefinition(pbd);
// 使用bd覆盖父定义
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
// 如果没有指定scope,那么设置默认的scope为单例
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
// 如果containingBd不为空 && containingBd不为singleton && mbd为singleton,则将mdb的scope设置为containingBd的scope
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
// 将beanName与mbd放到mergedBeanDefinitions缓存,以便之后可以直接使用
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
// 返回MergedBeanDefinition
return mbd;
}
}
![ ][nbsp 4]
6,ChildBeanDefinition
ChildBeanDefinition 继承自 AbstractBeanDefinition。其相当于一个子类,不可以单独存在,必须依赖一个父 BeanDetintion,构造 ChildBeanDefinition 时,通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。它可以从父类继承方法参数、属性值,并可以重写父类的方法,同时也可以增加新的属性或者方法。
从 Spring 2.5 开始,以编程方式注册 Bean 定义的首选方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的绝大分部使用场合。
7,AnnotatedBeanDefinition
AnnotatedBeanDefinition 是 BeanDefinition 子接口之一,该接口扩展了 BeanDefinition 的功能,其用来操作注解元数据。一般情况下,通过注解方式得到的 Bean(@Component、@Bean),其 BeanDefinition 类型都是该接口的实现类。
public interface AnnotatedBeanDefinition extends BeanDefinition {
// 获得当前 Bean 的注解元数据
AnnotationMetadata getMetadata();
// 获得当前 Bean 的工厂方法上的元数据
MethodMetadata getFactoryMethodMetadata();
}
该接口可以返回两个元数据的类:
- AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
- MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是 final 方法等。
8,ScannedGenericBeanDefinition
ScannedGenericBeanDefinition 继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 @Component 注解的 Bean,其派生注解如 @Service、@Controller 也同理。
其在源码中是在 loadBeanDefinition 时解析 xml 配置文件,如果包含 component-scan 标签,就扫描 component-scan 的 base-package 指定的包下包含@Component 注解(当然包括@Service,@Controller)的类,添加的 beanDefinitionMap 中注入进来。
![ ][nbsp 5]
9,AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition 继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述通过@Import 注解方式注入的 Bean。
10,ConfigurationClassBeanDefinition
ConfigurationClassBeanDefinition 继承自 RootBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述在标注 @Configuration 注解的类中,通过 @Bean 注解实例化的 Bean。
其功能特点如下:
- 如果 @Bean 注解没有指定 Bean 的名字,默认会用方法的名字命名 Bean。
- 标注 @Configuration 注解的类会成为一个工厂类,而标注 @Bean 注解的方法会成为工厂方法,通过工厂方法实例化 Bean,而不是直接通过构造方法初始化。
- 标注 @Bean 注解的类会使用构造方法自动装配。 [nbsp]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578247723.png [nbsp 1]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578248053.png [nbsp 2]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578248314.png [nbsp 3]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578248693.png [nbsp 4]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578249066.png [nbsp 5]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578249475.png