一、导读
BeanDefinition
是 Spring
框架中定义 Bean
的配置元信息接口,包含有:
- Bean的类名
- Bean行为配置元素,如
作用域
、自动绑定模式
、生命周期回调
(注解、方法)等 - 其他Bean引用,可称为
合作者(Collaborators)
或依赖(Dependencies)
- 配置设置,比如
Bean
属性(Properties) | 属性 | 说明 | | —- | —- | | Class | Bean全类名,必须是具体类,不能用抽象类或接口 | | Name | Bean的名称或ID | | Scope | Bean的作用域(singleton、prototype) | | Constructor arguments | Bean构造器参数(用于依赖注入) | | Properties | Bean属性设置(用于依赖注入) | | Autowiring Mode | Bean自动绑定模式(NO(default)、byType、byName) | | Lazy Initialization Mode | Bean延迟初始化模式(延迟、非延迟) | | Initialization Mothod | Bean初始化回调方法名称 | | Destruction Method | Bean销毁回调方法名称 |
对于 厨师
而言, BeanDefinition
就是一份菜谱,里面记录着一道菜从食材的选择到烹饪的火候等一系列操作,也像 曲谱
,由乐者奏出美妙 音符
♪。
二、从上帝视角看Spring的BeanDefinition体系结构
2.1 继承结构
2.2 剖析
1. AttributeAccessor
见名知义,属性获取接口。该接口定义了一个 通用的准则
获取任意实体的元数据。简单看一下该接口的方法:
// AttributeAccessor
public interface AttributeAccessor {
void setAttribute(String name, @Nullable Object value);
Object getAttribute(String name);
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
}
2. BeanMetadataElement
// BeanMetadataElement
//
public interface BeanMetadataElement {
/**
* Return the configuration source {@code Object} for this metadata element
* (may be {@code null}).
*/
@Nullable
default Object getSource() {
return null;
}
}
由Bean元数据元素实现,该对象携带一个资源对象。如下图所示:
可以理解 .class
源文件。当然,如果被在配置类中被@Bean
注解标注的话,那么此时的 getSource
方法返回的是 StandardMethodMetadata
对象。表示该 Bean
是来源于某个配置方法。如下图所示:
3.BeanDefinition
BeanDefinition
描述了一个bean实例,该实例具有属性值
、构造函数参数值
以及由具体实现类提供的更多信息。 这只是一个最小的接口:主要目的是允许BeanFactoryPostProcessor
内省和修改属性值
和其他Bean元数据信息。
说到 内省
,我们看一下里面的 setter
方法:
还有 isXX
方法:
是不是很熟悉,大致与我们常用的注解,如 @Lazy
、 @Primary
等对应。解释几个少见的:
- 生命周期回调方法
setInitMethodName
setDestroyMethodName
- 父类信息
getParentName()
- 获取构造函数参数
getConstructorArgumentValues()
获取setter
方法参数getPropertyValues()
- 创建此类的类名
setFactoryBeanName(@Nullable String factoryBeanName)
- 创建此类的方法名称
setFactoryMethodName(@Nullable String factoryMethodName);
当前 BeanDefinition
定义最基础的Bean信息,更丰富的信息,比如注解相关的,由子类完成。
4.AbstractBeanDefinition
抽象类,继承 BeanDefinition
接口,实现 BeanDefinition
绝大部分接口,但排除 GenericBeanDefinition
、 RootBeanDefinition
和 ChildBeanDefinition
常用属性。里面定义了接口所需要的 数据结构
以及赋予默认值。方便子类扩展。
5.GenericBeanDefinition
Generic: 通用的。
它可以灵活设置 parentName
属性值,从 父bean
中继承属性值,甚至可以通过 后置处理器
重新配置父名称。在父/子关系恰好是预先确定的地方使用 RootBeanDefinition / ChildBeanDefinition
。
6.ScannedGenericBeanDefinition
/**
* 基于ASM ClassReader的GenericBeanDefinition类的扩展,支持通过AnnotatedBeanDefinition接口获取注解元信息。
*
* 此类不会提早加载Bean类。
* 而是从ASM ClassReader解析的“.class”文件本身以检索所有相关的元数据。
* 它在功能上等效于AnnotatedGenericBeanDefinition.AnnotatedGenericBeanDefinition(AnnotationMetadata),
* 但按类型区分已扫描的bean 和 已通过其他方式注册或检测到的bean。
*
*/
@SuppressWarnings("serial")
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
/**
* 为给定的MetadataReader描述的类创建一个新的ScannedGenericBeanDefinition
* @param metadataReader the MetadataReader for the scanned target class
*/
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
setResource(metadataReader.getResource());
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public MethodMetadata getFactoryMethodMetadata() {
return null;
}
}
通过类扫描的都会变为此 ScannedGenericBeanDefinition
。
7.AnnotationGenericBeanDefinition
GenericBeanDefinition类的扩展,可以通过AnnotatedBeanDefinition接口暴露元注解信息。
//AnnotationGenericBeanDefinition
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
// 内省当前BeanClass进行注解元数据
this.metadata = AnnotationMetadata.introspect(beanClass);
}
在 Spring
内部中,使用 AnnotationConfigApplicationContext#register
或该类 构造方法
注册的 BeanDefinition
就是此类型。 注解@Import
导入的类也是此类型。
与ScannedGenericBeanDefinition区别
ScannedGenericBeanDefinition
是在将类路径扫描所得的类信息封装为此类型,采用的是 ASM
字节码技术,而 AnnotatedGenericBeanDefinition
使用标准反射API完成注解信息获取。
8.RootBeanDefinition
- 根bean定义表示已合并的bean definition,该definition在运行时支持Spring BeanFactory中的特定bean。
- 它可能是由多个相互继承的原始bean定义创建的,通常为GenericBeanDefinitions。
- root bean definition本质上是运行时的“统一”bean定义视图。
- 根Bean定义也可以在配置阶段用于注册各个Bean定义。
- 但是,从Spring 2.5开始,以编程方式注册bean定义的首选方法是GenericBeanDefinition类。
- GenericBeanDefinition的优点在于,它允许动态定义父项依赖项,而不是将角色“硬编码”为根bean定义
回顾Spring创建 RootBeanDefinition
,有以下几点:
- 在
AnnotationConfigApplicationContext
构造器中通过AnnotationConfigUtils
注册6个重要的Spring内建对象,都是使用RootBeanDefinition
封装。 - Spring在
DefaultListableBeanFactory#getMergedLocalBeanDefinition
返回的对象为RootBeanDefinition。
@Bean
解析生成的也是RootBeanDefinition(实际上是其子类ConfigurationClassBeanDefinition)
9.ChildBeanDefinition
从
Spring 2.5
开始,以编程的方式注册BeanDefinition
,首选是ChildBeanDefinition
,它可以动态定义父类依赖项。对大多数用例而言,使用GenericBeanDefinition
取代ChildBeanDefinition
。2.3 小结
相信各位看到这里,对
Spring
的BeanDefiniton
有个大概的了解。不同层次、不同类型的BeanDefinition
实现类表示拥有不同的能力。具有结构性的接口继承,便于维护和管理。在Spring
内部使用RootBeanDefinition
来做最后的菜谱,从里面获取配置信息实例化Bean对象。三、BeanDefinition合并操作
若类存在继承关系,需要获取
merge beandefiniton
完成对BeanDefinition
意义上的继承
。显而意见父
BeanDefinition
存在,子不存在,则子类继承其没有的属性值。- 若父、子存在相同属性,子不会被父类属性覆盖。
即没有的的拿过来,有的就不用管。