死磕Spring之IoC篇 - Bean 的“前身”
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读
Spring 版本:5.1.14.RELEASE
开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章
Bean 的“前身”
我们在 Spring 中通常以这两种方式定义一个 Bean:面向资源(XML、Properties)、面向注解。如今 Spring Boot 被广泛应用,通过注解定义一个 Bean 的方式变得更为普遍,因为在实际的开发过程中注解的方式相比于 XML 文件更加轻便,可以有效地提高工作效率。你是否这了解这两种方式在 Spring 内是如何进行处理的,将我们的配置信息转换成 Spring Bean,并管理着这些它们的生命周期
在 Spring Bean 的生命周期 可以看到,BeanDefinition 可以说是 Bean 的“前身”,首先进入 Bean 的元信息的配置、解析和注册阶段,然后才开始 Bean 的实例化和初始化等工作。接下来,我们就一起来看看 Bean 的“前身”是什么
BeanDefinition 是 Spring Framework 中定义 Bean 的配置元信息接口,主要包含一下信息:
- Bean 的类名
- Bean 行为配置类,如作用域、自动绑定模式、生命周期回调等
- 其他 Bean 引用,又可称作合作者或者依赖
- 配置设置,比如 Bean 属性
BeanDefinition 体系结构
org.springframework.beans.factory.config.BeanDefinition
接口的类图如下所示:
总览:
org.springframework.core.AttributeAccessor
接口,用于获取元数据,在实现类中通过 LinkedHashMap 集合保存元数据,例如通过 XML 的<meta />
标签定义的一些元信息会保存在其中org.springframework.beans.BeanMetadataElement
接口,用于获取定义 Bean 的源对象,在实现类中通过 Object 对象保存,所谓的源对象就是定义这个 Bean 的资源(XML 标签对象或者 .class 文件资源对象)
org.springframework.beans.factory.config.BeanDefinition
接口,定义一个 Bean 的元信息org.springframework.beans.factory.support.AbstractBeanDefinition
抽象类,实现 BeanDefinition 接口,包含了一个 Bean 几乎所有的元信息org.springframework.beans.factory.support.GenericBeanDefinition
,继承 AbstractBeanDefinition 抽象类,多了一个parentName
,表示有继承关系,是一个标准 Bean 元信息对象,通过 XML 定义的 Bean 会解析成该对象org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
接口,继承 BeanDefinition 接口,定义注解类的元信息,例如通过@Component
注解定义的 Bean,那么注解类的元信息会包含编译后的 .class 文件的所有信息org.springframework.context.annotation.ScannedGenericBeanDefinition
,继承 GenericBeanDefinition,实现 AnnotatedBeanDefinition 接口,多了一个 AnnotationMetadata 注解类元信息对象,例如通过@Component
注解定义的 Bean 会解析成该对象org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
,继承 GenericBeanDefinition,实现 AnnotatedBeanDefinition 接口,和 ScannedGenericBeanDefinition 类似,通过@Import
导入的Configuration Class
会解析成该对象
org.springframework.beans.factory.support.RootBeanDefinition
,继承 AbstractBeanDefinition 抽象类,表示合并后的 BeanDefinition 对象。在 Spring BeanFactory 初始化 Bean 的前阶段,会根据 BeanDefinition 生成一个 RootBeanDefinition(具有层次性则会进行合并),用于后续实例化和初始化org.springframework.context.annotation.ConfigurationClassBeanDefinition$ConfigurationClassBeanDefinition
私有静态类,继承 RootBeanDefinition,实现了 AnnotatedBeanDefinition 接口,和 AnnotatedGenericBeanDefinition 类似,没有继承关系,通过@Bean
定义的方法会解析成该对象
org.springframework.beans.factory.config.BeanDefinitionHolder
,包含 BeanDefinition、Bean 的名称以及别名(支持多个)
总结一下,BeanDefinition 接口的实现类主要根据 Bean 的定义方式进行区分,如下:
XML 定义 Bean >>>>> GenericBeanDefinition
@Component 以及派生注解定义 Bean >>>>> ScannedGenericBeanDefinition
借助于 @Import 导入 Bean >>>>> AnnotatedGenericBeanDefinition
@Bean 定义的方法 >>>>> ConfigurationClassBeanDefinition
在 Spring BeanFactory 初始化 Bean 的前阶段,会根据 BeanDefinition 生成一个合并后的 RootBeanDefinition 对象
BeanDefinition 接口
org.springframework.beans.factory.config.BeanDefinition
接口,继承 AttributeAccessor 和 BeanMetadataElement 两个接口,定义一个 Bean 的元信息
BeanDefinition 内部就定义了获取一些基础元信息的方法,可跳转 BeanDefinition.java 查看
AbstractBeanDefinition 抽象类
org.springframework.beans.factory.support.AbstractBeanDefinition
抽象类,实现 BeanDefinition 接口,继承 BeanMetadataAttributeAccessor 类(AttributeAccessor 和 BeanMetadataElement 的实现类),包含了一个 Bean 几乎所有的元信息,可跳转 AbstractBeanDefinition.java 查看,下面列举最常见的属性:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
@Nullable
private volatile Object beanClass;
private boolean abstractFlag = false;
private boolean lazyInit = false;
@Nullable
private String[] dependsOn;
private boolean primary = false;
private boolean nonPublicAccessAllowed = true;
@Nullable
private String factoryBeanName;
@Nullable
private String factoryMethodName;
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
@Nullable
private MutablePropertyValues propertyValues;
@Nullable
private String initMethodName;
@Nullable
private String destroyMethodName;
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;
private boolean synthetic = false;
private int role = BeanDefinition.ROLE_APPLICATION;
@Nullable
private String description;
@Nullable
private Resource resource;
// ... 省略大量代码
}
GenericBeanDefinition
org.springframework.beans.factory.support.GenericBeanDefinition
,继承 AbstractBeanDefinition 抽象类,多了一个 parentName
,表示有继承关系,是一个标准 Bean 元信息对象,通过 XML 定义的 Bean 会解析成该对象,代码如下:
public class GenericBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
public GenericBeanDefinition() {
super();
}
public GenericBeanDefinition(BeanDefinition original) {
super(original);
}
// ... 省略相关方法
}
AnnotatedBeanDefinition 接口
org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
接口,继承 BeanDefinition 接口,定义注解类的元信息,代码如下:
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
* @return the annotation metadata object (never {@code null})
*/
AnnotationMetadata getMetadata();
/**
* Obtain metadata for this bean definition's factory method, if any.
* @return the factory method metadata, or {@code null} if none
* @since 4.1.1
*/
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
AnnotationMetadata 可以获取到定义 Bean 的所有信息,在 Spring 底层会通过 ASM(一个操作 Java 字节码与分析的框架)实现的
MethodMetadata 可以获取到工厂方法的元信息,目前我没发现哪里使用到
例如通过 @Component
注解定义的 Bean,那么 AnnotationMetadata 可以获取到这个 Class 对象的所有信息
ScannedGenericBeanDefinition
org.springframework.context.annotation.ScannedGenericBeanDefinition
,继承 GenericBeanDefinition,实现 AnnotatedBeanDefinition 接口,多了一个 AnnotationMetadata 注解类元信息对象,例如通过 @Component
注解定义的 Bean 会解析成该对象,代码如下:
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public MethodMetadata getFactoryMethodMetadata() {
return null;
}
}
AnnotatedGenericBeanDefinition
org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
,继承 GenericBeanDefinition,实现 AnnotatedBeanDefinition 接口,和 ScannedGenericBeanDefinition 类似,代码如下:
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {
this(metadata);
Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");
setFactoryMethodName(factoryMethodMetadata.getMethodName());
this.factoryMethodMetadata = factoryMethodMetadata;
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
}
通过 @Import
导入的 Configuration Class
会解析成该对象,不过 factoryMethodMetadata
还是为 null
RootBeanDefinition
org.springframework.beans.factory.support.RootBeanDefinition
,继承 AbstractBeanDefinition 抽象类,表示合并后的 BeanDefinition 对象
在 Spring BeanFactory 初始化 Bean 的前阶段,会根据 BeanDefinition 生成一个 RootBeanDefinition(具有层次性则会进行合并),用于后续实例化和初始化
可跳转 RootBeanDefinition.java 查看
BeanDefinitionHolder
org.springframework.beans.factory.config.BeanDefinitionHolder
,包含 BeanDefinition、Bean 的名称以及别名(支持多个),代码如下:
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
@Nullable
private final String[] aliases;
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
this(beanDefinition, beanName, null);
}
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, @Nullable String[] aliases) {
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
Assert.notNull(beanName, "Bean name must not be null");
this.beanDefinition = beanDefinition;
this.beanName = beanName;
this.aliases = aliases;
}
}
在解析出来 BeanDefinition 后都会转换成 BeanDefinitionHolder 对象,然后进行注册
总结
Spring Bean 的“前身”为 BeanDefinition 对象,里面包含了 Bean 的元信息,后续在 Bean 的生命周期中会根据该对象进行实例化和初始化等工作
BeanDefinition 接口的实现类主要根据 Bean 的定义方式进行区分,如下:
XML 定义 Bean:GenericBeanDefinition
@Component 以及派生注解定义 Bean:ScannedGenericBeanDefinition
借助于 @Import 导入 Bean:AnnotatedGenericBeanDefinition
@Bean 定义的方法:ConfigurationClassBeanDefinition 私有静态类
上面的 1
、2
、3
三种 BeanDefinition 实现类具有层次性,在 Spring BeanFactory 初始化 Bean 的前阶段,会根据 BeanDefinition 生成一个合并后的 RootBeanDefinition 对象
死磕Spring之IoC篇 - Bean 的“前身”的更多相关文章
- 死磕Spring之IoC篇 - Bean 的创建过程
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - @Bean 等注解的实现原理
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - 文章导读
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - 开启 Bean 的加载
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的加载阶段(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - @Autowired 等注解的实现原理
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
随机推荐
- 设计模式c++(3)——观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖着都会收到通知并自动更新. 当两个对象之间松耦合,他们依然可以交互,但是不太清楚彼此的细节.观察者模式提供了一种对象设 ...
- pugixml应用随笔
1. 修改元素值 second_node.set_value("miller");不对 必须second_node.first_child().set_value(" ...
- 5. Linux文件目录管理和打包压缩与搜索命令
1.touch:用于创建空白文件或设置文件的时间 举例:使用ls 命令查看一个文件的修改时间,然后修改这个文件,最后再通过touch命令把修改后的文件时间设置成修改之前的时间(很多黑客就是这样做的): ...
- 前端html基础学习笔记二
表单 1 : 表单标签 <form></form> 属性 : action = '接口地址' method = 'get / post' name = '表单名称' 2 : 表 ...
- impala支持的数据库里的double(float)类型,通过迁移inceptor后,类型的值都变成了null
impala支持的数据库里的double(float)类型,通过迁移inceptor后,double类型的值都变成了null. 通过查阅日志发现默认将double转换成Decimal(38,10)然而 ...
- B. Modular Equations
Last week, Hamed learned about a new type of equations in his math class called Modular Equations. L ...
- Codeforces Round #636div3 D. Constant Palindrome Sum (划分区间,差分)
题意:给你一个长度为偶数n的数组,每次可以将一个元素修改为不大于k的值,要求每个a[i]+a[n-i+1]都相等,求最少操作多少次 题解:假设每一对的和都为sum,小的记为mn,大的记为mx; ...
- Codeforces Round #241 (Div. 2) B. Art Union (DP)
题意:有\(n\)个画家,\(m\)幅画,每个画家负责\(m\)幅画,只有前一个画家画完时,后面一个画家才能接着画,一个画家画完某幅画的任务后,可以开始画下一幅画的任务,问每幅画最后一个任务完成时的时 ...
- Chapter Zero 0.2.1 执行运算与判断的CPU
目录 执行运算与判断的CPU CPU效能比较的指标 CPU的工作频率:外频与倍频 32位与64位的CPU与总线[宽度] CPU的等级 超线程(Hyper-Threading,HT) 网上摘下几张主板图 ...
- 操作系统 part4
1.操作系统的启动 CPU加电后,执行BIOS(基本IO处理系统).BIOS会进行硬件的自检和初始化,然后把加载程序(BootLoader)从磁盘上的引导扇区中加载到指定位置0x7c00.然后控制权交 ...