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