1. BeanDefinition是什么
在 Spring 中,BeanDefinition 是一个接口,用于描述一个 bean 对象,它是Spring创建 bean 的基石。其中保存了一个 bean 对象的元数据,比如:bean 的 Class 信息、作用域 (单例 or 原型)、依赖关系、初始化方法、销毁方法等信息。接口中相关方法如下(主要是一些get/set方法,没有复杂功能):
Spring 在启动过程就是通过 BeanDefinition 所提供的信息来创建 bean 对象的。 无论我们使用哪种 bean 的配置方式(注解 或 XML),Spring 在启动时都会解析这些配置,然后生成相应的 BeanDefinition 对象。这些 BeanDefinition 对象就像是 Spring 容器内部生成 bean 模板,告诉Spring容器如何创建和配置各个 Bean。
2. BeanDefinition的实现类
BeanDefinition 接口的实现类如下:
我们知道接口是对行为的一种抽象,通常用来定义有什么功能。而抽象类的主要目的是封装公共逻辑,复用代码。 上述 BeanDefinition 的实现类中,所有实现类都直接或间接的继承自 AbstractBeanDefinition,AbstractBeanDefinition 中定义了公共属性和公共方法。接下来介绍一下 BeanDefinition 的各个实现类。
2.1 ChildBeanDefinition
Spring 是支持 bean 继承的(这个平时用的并不多,了解即可),ChildBeanDefinition 正是用于继承父级 BeanDefinition 的 bean 定义。在解析 ChildBeanDefinition 的时候,会把父级 BeanDefinition 的属性拷贝给 ChildBeanDefinition。
具体来说,ChildBeanDefinition 内部持有一个标识父级 BeanDefinition 的属性parentName
。需要注意的是 ChildBeanDefinition 没有对外暴露修改parentName
的方法,所以 ChildBeanDefinition 一旦创建,父子关系就是不可改变的了。
public class ChildBeanDefinition extends AbstractBeanDefinition {
// 父 BeanDefinition 名称
@Nullable
private String parentName;
}
注:Spring2.5 之后,推荐使用 GenericBeanDefinition 注册 BeanDefinition,我们可以通过
GenericBeanDefinition#setParentName
方法动态地设定父子依赖关系,GenericBeanDefinition 在大多数情况下取代了 ChildBeanDefinition。
2.2 GenericBeanDefinition
GenericBeanDefinition 是一个标准bean定义(我们自定义的大部分 bean 都会用这个类实现注册),同样可以设置父子关系(相比ChildBeanDefinition更加灵活)。如果在开发过程中,你需要通过编码的方式往 Spring 容器里注册BeanDefinition,Spring 更加推荐使用这个类来进行 bean 定义信息的注册。
一般来说,Spring 会使用 GenericBeanDefinition 类来注册我们自己所声明的bean(比如 XML 配置文件声明的bean)。
2.3. AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition 是对 GenericBeanDefinition 的扩展,增加了对于注解元数据的支持。我们平时写的配置类(即@Configuration
注解标注的类)会被封装成AnnotatedGenericBeanDefinition
,然后注册到 BeanDefinitionRegistry。
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
// 注解元数据
private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;
// 省略其余代码.
}
2.4. ScannedGenericBeanDefinition
ScannedGenericBeanDefinition 功能上等同于2.3中的 AnnotatedGenericBeanDefinition,只是为了区分通过 扫描和其他方式得到的 BeanDefinition。
比如说,被组件扫描加载的 bean (@Component
、@Repository
、@Service
、@Controller
)会以ScannedGenericBeanDefinition 的形式进行注册。
2.5 RootBeanDefinition
RootBeanDefinition 是所有bean定义信息在 Spring 运行时的统一视图。它是一个最完整的BeanDefinition,表示在运行时某个 bean 定义经过合并之后的 bean 定义(可能合并,也可能不合并,如果有父 BeanDefinition 就会合并)。
Spring 启动阶段,所有的 BeanDefinition 都会最终转换为RootBeanDefinition。
RootBeanDefinition 可以用于在配置阶段注册单个Bean定义。但是,自Spring 2.5 以后,以编程方式注册Bean定义的首选方式是 GenericBeanDefinition 类。GenericBean定义的优点在于它允许动态定义父依赖关系。
Spring 内置的 Bean 注册的都是通过创建 RootBeanDefiniton 的形式进行注册的,比如用于解析@Configuration、@Autowaire等注解的后置处理器的注册:
2.6 ConfigurationClassBeanDefinition
ConfigurationClassBeanDefinition 是 ConfigurationClassBeanDefinitionReader 的私有静态内部类。正如类名所表达的,它表示在配置类中的 Bean 定义,也即通过@Bean
注解定义的 bean 会被封装成 ConfigurationClassBeanDefinition。
2.7 ClassDerivedBeanDefinition
这是一个定义在 GenericApplicationContext 中的静态内部类,专门用于封装通过GenericApplicationContext#registerBean
方法注册的 Bean 定义信息。通过类图可知,它继承自 RootBeanDefinition,没有添加额外的功能,主要目的是作为一种标识,用于识别来自registerBean
方法注册的 bean。
3. 总结
这篇文章主要介绍了 Spring 中各种 BeanDefinition 的实现,所有 BeanDefinition 在 Spring 运行时最终都会被转换成 RootBeanDefinition(后续文章会进行介绍)。真正开发过程中,我们并不需要关心 Spring 为某个 bean 创建的是哪一种 BeanDefinition。Spring会自动管理这些 BeanDefinition,并根据它们的类型以及它们所包含的信息来创建和配置bean。
虽然平时开发可能根本用不到 BeanDefinition,但却是搞懂 Spring 原理的基础,可以帮助我们更进一步的了解 Spring 的运行原理。