该系列文章是本人在学习 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 的定义方式进行区分,如下:

  1. XML 定义 Bean >>>>> GenericBeanDefinition

  2. @Component 以及派生注解定义 Bean >>>>> ScannedGenericBeanDefinition

  3. 借助于 @Import 导入 Bean >>>>> AnnotatedGenericBeanDefinition

  4. @Bean 定义的方法 >>>>> ConfigurationClassBeanDefinition

  5. 在 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 的定义方式进行区分,如下:

  1. XML 定义 Bean:GenericBeanDefinition

  2. @Component 以及派生注解定义 Bean:ScannedGenericBeanDefinition

  3. 借助于 @Import 导入 Bean:AnnotatedGenericBeanDefinition

  4. @Bean 定义的方法:ConfigurationClassBeanDefinition 私有静态类

上面的 123 三种 BeanDefinition 实现类具有层次性,在 Spring BeanFactory 初始化 Bean 的前阶段,会根据 BeanDefinition 生成一个合并后的 RootBeanDefinition 对象

死磕Spring之IoC篇 - Bean 的“前身”的更多相关文章

  1. 死磕Spring之IoC篇 - Bean 的创建过程

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  2. 死磕Spring之IoC篇 - @Bean 等注解的实现原理

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  3. 死磕Spring之IoC篇 - 文章导读

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  4. 死磕Spring之IoC篇 - 开启 Bean 的加载

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  5. 死磕Spring之IoC篇 - BeanDefinition 的加载阶段(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  6. 死磕Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  7. 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  8. 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  9. 死磕Spring之IoC篇 - @Autowired 等注解的实现原理

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

随机推荐

  1. 调用个别f5 负载端口为80的vs时,返回值为空的问题

    现状: vs负载端口为80并添加XFF,pool包含2个member,member的monitor端口为80&9000. 故障现象: 应用同事描述说再完全复制了一个member并添加到pool ...

  2. 从ReentrantLock实现非公平锁的源码理解AQS中的CLH队列

    虽然前面也看过AQS的文章,并且转载过一篇大佬的分析,但是我觉得他们对于AQS和ReentrantLock部分的源码的分析并不详细,自己理解期来还是有问题,于是自己准备花时间重新梳理下,好了,进入正题 ...

  3. maven高级笔记

    Maven高级 1.maven基础知识回顾 1.1 maven介绍 maven 是一个项目管理工具,主要作用是在项目开发阶段对Java项目进行依赖管理和项目构建. 依赖管理:就是对jar包的管理.通过 ...

  4. centos 7 部署nginx及libfastcommon

    1.编译环境 (centos)yum install git gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib- ...

  5. vue-cli3移动端自适应配置 Vant组件库

    module.exports = { presets: [ '@vue/app' ], plugins: [ ['import', { libraryName: 'vant', libraryDire ...

  6. vector总结

    vector是不定长数组,具有静态数组的稳定性和动态分配内存的灵活性,在赛场上不失为指针之外牺牲部分时间的保险之举. 本文先介绍一些vector常用的函数(部分借鉴一篇博客中的内容 链接),并以此为铺 ...

  7. Strategic game POJ - 1463 树型dp

    //题意:就是你需要派最少的士兵来巡查每一条边.相当于求最少点覆盖,用最少的点将所有边都覆盖掉//题解://因为这是一棵树,所以对于每一条边的两个端点,肯定要至少有一个点需要放入士兵,那么对于x-&g ...

  8. 加密算法——RSA算法(c++简单实现)

    RSA算法原理转自:https://www.cnblogs.com/idreamo/p/9411265.html C++代码实现部分为本文新加 RSA算法简介 RSA是最流行的非对称加密算法之一.也被 ...

  9. 牛客编程巅峰赛S1第6场 - 黄金&钻石&王者 B.牛牛摆放花 (贪心)

    题意;将一组数重新排序,使得相邻两个数之间的最大差值最小. 题解:贪心,现将所有数sort一下,然后正向遍历,将数分配到新数组的两端,然后再遍历一次维护一个最大值即可. 代码: class Solut ...

  10. windows7 更新失败,无法开机处理方法

    记录一次今天同事笔记本无法开机的故障处理 windows7系统,安装更新失败,无法开机,卡在配置更新界面 处理方法,强制关机,开机按F8,进入安全模式,安全模式还会卡在配置更新界面,但是卡一会会进入系 ...