Spring 源码学习 05:BeanDefinition 概念及其实现
前言
BeanDefinition:顾名思义,就是 Bean 的定义,是用来描述一个 Bean 都有什么信息。前面说在初始化 DefaultListableBeanFactory
时,会初始化一个 Map<String, BeanDefinition>
,这个 Map 的功能暂且不说,(PS:查资料说的是存储 bean),所以今天就结合官方文档以及源码,一起了解一下 BeanDefinition
!
概念
在容器内部,使用 BeanDefinition
对象定义一个 Bean。而定义的信息包含 类名、作用域、是否懒加载、构造参数、初始化方法、销毁方式等等。
了解了概念之后,开始阅读源码,源码部分比较长。
源码介绍
通过 UML 可以看出 BeanDefinition 接口继承了 AttributeAccessor 和 BeanMetadataElement 两个接口。
AttributeAccessor
AttributeAccessor:定义用于将元数据附加到任意对象或从任意对象访问元数据的通用协定的接口。
public interface AttributeAccessor {
void setAttribute(String name, @Nullable Object value);
@Nullable
Object getAttribute(String name);
@Nullable
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
}
通过接口方法可以看出,AttributeAccessor 主要定义了对元数据属性
的增删改查。
AttributeAccessorSupport
是 AttributeAccessor 接口的一个实现,通过实现可以看出,其内部使用了 Map 保存名称和属性值。
BeanMetadataElement
BeanMetadataElement:由包含配置源对象的 bean 元数据元素实现的接口。
public interface BeanMetadataElement {
@Nullable
default Object getSource() {
return null;
}
}
接口内部只有一个 getSource()
方法,其含义为:返回此元数据元素的配置源Object (可以为null )。
其实还是不知道啥意思……
在子类(BeanMetadataAttributeAccessor
)中加上断点,debug
这里 source 里面存储了 Class 类文件在磁盘的真实路径。当然姑且可以这么认为,毕竟我这也是刚开始学习源码,当前的结论只是 debug 到的,也有可能在别的实现类中存储的是别的信息。
BeanDefinition
BeanDefinition 方法较多,就不贴代码,或者截图了。详细可以通过 我的 GitHub 进行阅读,上面添加了相关注释。
不过还是简要介绍一下方法,大概有 Bean 的名字、作用范围、是否首选、以及 Bean 的初始化销毁方法等等。
BeanDefinition 只是一个接口,其实现又分为好几种。
AbstractBeanDefinition
AbstractBeanDefinition 作为 BeanDefinition 的抽象实现类,内部定义了很多属性,以满足 BeanDefinition 定义的接口功能。
这些属性的操作,就对应着 BeanDefinition 定义的接口方法。
AbstractBeanDefinition 的三个实现类
AbstractBeanDefinition 的实现又分为三个:分别是 ChildBeanDefinition
、 RootBeanDefinition
、 GenericBeanDefinition
。
-
ChildBeanDefinition:可以从 Parent Definition 里面继承一些公共定义(初始化方法、销毁方法、是否懒加载等等)不过
-
RootBeanDefinition:定义 Bean Definition 的公共属性,该定义在运行时支持Spring BeanFactory中的特定bean。 而 RootBeanDefinition 是不可以设置 parentName 指定 Parent Definition 的。
-
GenericBeanDefinition:是一个通用的 Bean Definition,是一站式服务,用于标准bean定义。 像任何bean定义一样,它允许指定一个类以及可选的构造函数参数值和属性值。 另外,可以通过
parentName
属性灵活地配置从父bean定义派生的内容。所以现在一般使用 GenericBeanDefinition。
从 Spring 2.5 开始,以编程方式注册 Bean Definition 的首选方法是 GenericBeanDefinition 类,该类允许通过 GenericBeanDefinition.setParentName 方法动态定义父依赖项。
GenericBeanDefinition 下面还有两个实现:ScannedGenericBeanDefinition
、AnnotatedGenericBeanDefinition
。
二者并无太大区别,只不过 AnnotatedGenericBeanDefinition
比 ScannedGenericBeanDefinition
多了一个 factoryMethodMetadata
的定义。
总结
通过阅读 BeanDefinition 的源码,并对其实现类的源码进行阅读之后,大致了解 BeanDefinition 的概念及其含义。大概作图总结如下: