死磕Spring之IoC篇 - Bean 的“前身”


該系列文章是本人在學習 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 對象


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM