• 死磕Spring之IoC篇


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

    Spring 版本:5.1.14.RELEASE

    开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章

    该系列其他文章请查看:《死磕 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 对象

  • 相关阅读:
    0STM32F407+ESP8266基本控制篇(自建物联网平台)整体运行测试微信小程序使用APUConfig配网绑定ESP8266,并通过MQTT实现远程通信控制
    0STM32F407+ESP8266基本控制篇(自建物联网平台)整体运行测试Android使用APUConfig配网绑定ESP8266,并通过MQTT实现远程通信控制
    14STM32F407+ESP8266基本控制篇(自建物联网平台)STM32F407+ESP8266以SSL单向认证方式连接MQTT服务器(不验证服务器证书)
    003STM32F407+ESP8266基本控制篇(阿里云物联网平台)在阿里云物联网平台上一型一密动态注册设备(STM32F407+ESP8266)
    02STM32F407+ESP8266基本控制篇(自建物联网平台)硬件使用说明
    001STM32F407+ESP8266基本控制篇(阿里云物联网平台)C#,网页,android,微信小程序,单片机等使用MQTT接入阿里云物联网平台
    6STM32+ESP8266+Air302远程升级篇(自建物联网平台)STM32通过air302使用http下载程序文件,升级程序(手机APP控制更新)
    4STM32+ESP8266+Air302远程升级篇(自建物联网平台)STM32通过ESP8266使用http或https下载程序文件,升级程序(手机APP控制更新)
    3STM32+ESP8266+Air302远程升级篇(自建物联网平台)STM32+mbedtls通过air302使用https下载程序文件,升级程序(单片机程序轮训检查更新)
    面试官:你真的了解Redis分布式锁吗?
  • 原文地址:https://www.cnblogs.com/lifullmoon/p/14434009.html
Copyright © 2020-2023  润新知