死磕Spring之IoC篇 - Bean 的「前身」

該系列文章是本人在學習 Spring 的過程當中總結下來的,裏面涉及到相關源碼,可能對讀者不太友好,請結合個人源碼註釋 Spring 源碼分析 GitHub 地址 進行閱讀html

Spring 版本:5.1.14.RELEASEjava

開始閱讀這一系列文章以前,建議先查看《深刻了解 Spring IoC(面試題)》這一篇文章git

該系列其餘文章請查看:《死磕 Spring 之 IoC 篇 - 文章導讀》github

Bean 的「前身」

咱們在 Spring 中一般以這兩種方式定義一個 Bean:面向資源(XML、Properties)面向註解。現在 Spring Boot 被普遍應用,經過註解定義一個 Bean 的方式變得更爲廣泛,由於在實際的開發過程當中註解的方式相比於 XML 文件更加輕便,能夠有效地提升工做效率。你是否這瞭解這兩種方式在 Spring 內是如何進行處理的,將咱們的配置信息轉換成 Spring Bean,並管理着這些它們的生命週期面試

Spring Bean 的生命週期 能夠看到,BeanDefinition 能夠說是 Bean 的「前身」,首先進入 Bean 的元信息的配置、解析和註冊階段,而後纔開始 Bean 的實例化和初始化等工做。接下來,咱們就一塊兒來看看 Bean 的「前身」是什麼spring

BeanDefinition 是 Spring Framework 中定義 Bean 的配置元信息接口,主要包含一下信息:框架

  • Bean 的類名
  • Bean 行爲配置類,如做用域、自動綁定模式、生命週期回調等
  • 其餘 Bean 引用,又可稱做合做者或者依賴
  • 配置設置,好比 Bean 屬性

BeanDefinition 體系結構

org.springframework.beans.factory.config.BeanDefinition 接口的類圖以下所示:ide

總覽:源碼分析


  • 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 對象

相關文章
相關標籤/搜索