前言
在上篇文章中,我們討論了 refresh 的前四個方法,主要是對 ApplicationContext 上下文啟動做一些准備工作。原計划是對接下來的 invokeBeanFactoryPostProcessors 方法進行討論,但該方法涉及 Spring 中一個非常重要的概念: BeanDefinition,所以,這里先對 BeanDefinition 進行討論,這樣也有利於完善 Spring 的知識體系。
注:本篇文章使用的 SpringBoot 版本為 2.0.3.RELEASE,其 Spring 版本為 5.0.7.RELEASE
正文
現如今,我們一般獲取對象的方式有兩種,一種是手動直接 new;另一種是交給 Spring 管理,Spring 將管理的對象稱之為 Bean,容器會先實例化 Bean,然后自動注入,實例化的過程就需要依賴 BeanDefinition。
BeanDefinition 用於保存 Bean 的相關信息,包括屬性、構造方法參數、依賴的 Bean 名稱及是否單例、延遲加載等,它是實例化 Bean 的原材料,Spring 就是根據 BeanDefinition 中的信息實例化 Bean。
BeanDefinition的繼承體系
BeanDefinition 是一個接口,它有多個實現類,這些實現類分別描述不同類型的 Bean。
BeanDefinition
一個 BeanDefinition 描述了一個 Bean 實例,實例包含屬性值、構造方法參數值以及更多實現信息。該 BeanDefinition 只是是一個最小的接口,主要目的是允許修改屬性值和其他 Bean 元數據,這里列出幾個核心方法。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 單例、原型標識符
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// 標識 Bean 的類別,分別對應 用戶定義的 Bean、來源於配置文件的 Bean、Spring 內部的 Bean
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
// 設置、返回 Bean 的父類名稱
void setParentName(@Nullable String parentName);
String getParentName();
// 設置、返回 Bean 的 className
void setBeanClassName(@Nullable String beanClassName);
String getBeanClassName();
// 設置、返回 Bean 的作用域
void setScope(@Nullable String scope);
String getScope();
// 設置、返回 Bean 是否懶加載
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 設置、返回當前 Bean 所依賴的其它 Bean 名稱。
void setDependsOn(@Nullable String... dependsOn);
String[] getDependsOn();
// 設置、返回 Bean 是否可以自動注入。只對 @Autowired 注解有效
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 設置、返回當前 Bean 是否為主要候選 Bean 。
// 當同一個接口有多個實現類時,通過該屬性來配置某個 Bean 為主候選 Bean。
void setPrimary(boolean primary);
boolean isPrimary();
// 設置、返回創建該 Bean 的工廠類。
void setFactoryBeanName(@Nullable String factoryBeanName);
String getFactoryBeanName();
// 設置、返回創建該 Bean 的工廠方法
void setFactoryMethodName(@Nullable String factoryMethodName);
String getFactoryMethodName();
// 返回該 Bean 構造方法參數值、所有屬性
ConstructorArgumentValues getConstructorArgumentValues();
MutablePropertyValues getPropertyValues();
// 返回該 Bean 是否是單例、是否是非單例、是否是抽象的
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
// 返回 Bean 的類別。類別對應上面的三個屬性值。
int getRole();
...
}
可以看到 BeanDefinition 接口提供了一系列操作 Bean 元數據的set、get方法,這些操作為 Bean 的描述定義了一套模板,具體的實現則交由子類。
AnnotatedBeanDefinition
AnnotatedBeanDefinition 是 BeanDefinition 子接口之一,該接口擴展了 BeanDefinition 的功能,其用來操作注解元數據。一般情況下,通過注解方式得到的 Bean(@Component、@Bean),其 BeanDefinition 類型都是該接口的實現類。
public interface AnnotatedBeanDefinition extends BeanDefinition {
// 獲得當前 Bean 的注解元數據
AnnotationMetadata getMetadata();
// 獲得當前 Bean 的工廠方法上的元數據
MethodMetadata getFactoryMethodMetadata();
}
該接口可以返回兩個元數據的類:
-
AnnotationMetadata:主要對 Bean 的注解信息進行操作,如:獲取當前 Bean 標注的所有注解、判斷是否包含指定注解。
-
MethodMetadata:方法的元數據類。提供獲取方法名稱、此方法所屬類的全類名、是否是抽象方法、判斷是否是靜態方法、判斷是否是final方法等。
AbstractBeanDefinition
AbstractBeanDefinition 是 BeanDefinition 的子抽象類,也是其他 BeanDefinition 類型的基類,其實現了接口中定義的一系列操作方法,並定義了一系列的常量屬性,這些常量會直接影響到 Spring 實例化 Bean 時的策略。核心屬性如下。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// 默認的 SCOPE,默認是單例
public static final String SCOPE_DEFAULT = "";
// 不進行自動裝配
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
// 根據 Bean 的名字進行自動裝配,byName
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
// 根據 Bean 的類型進行自動裝配,byType
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
// 根據構造器進行自動裝配
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
// 首先嘗試按構造器自動裝配。如果失敗,再嘗試使用 byType 進行自動裝配。(Spring 3.0 之后已廢除)
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
// 通過依賴檢查來查看 Bean 的每個屬性是否都設置完成
// 以下常量分別對應:不檢查、對依賴對象檢查、對基本類型,字符串和集合進行檢查、對全部屬性進行檢查
public static final int DEPENDENCY_CHECK_NONE = 0;
public static final int DEPENDENCY_CHECK_OBJECTS = 1;
public static final int DEPENDENCY_CHECK_SIMPLE = 2;
public static final int DEPENDENCY_CHECK_ALL = 3;
// 關閉應用上下文時需調用的方法名稱
public static final String INFER_METHOD = "(inferred)";
// 存放 Bean 的 Class 對象
private volatile Object beanClass;
// Bean 的作用范圍
private String scope = SCOPE_DEFAULT;
// 非抽象
private boolean abstractFlag = false;
// 非延遲加載
private boolean lazyInit = false;
// 默認不自動裝配
private int autowireMode = AUTOWIRE_NO;
// 默認不依賴檢查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// 依賴的 Bean 列表
private String[] dependsOn;
// 可以作為自動裝配的候選者,意味着可以自動裝配到其他 Bean 的某個屬性中
private boolean autowireCandidate = true;
// 創建當前 Bean 實例工廠類名稱
private String factoryBeanName;
// 創建當前 Bean 實例工廠類中方法名稱
private String factoryMethodName;
// 存儲構造方法的參數
private ConstructorArgumentValues constructorArgumentValues;
// 存儲 Bean 屬性名稱以及對應的值
private MutablePropertyValues propertyValues;
// 存儲被覆蓋的方法信息
private MethodOverrides methodOverrides;
// init、destroy 方法名稱
private String initMethodName;
private String destroyMethodName;
// 是否執行 init 和 destroy 方法
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;
// Bean 是否是用戶定義的而不是應用程序本身定義的
private boolean synthetic = false;
// Bean 的身份類別,默認是用戶定義的 Bean
private int role = BeanDefinition.ROLE_APPLICATION;
// Bean 的描述信息
private String description;
// Bean 定義的資源
private Resource resource;
...
}
以上是 AbstractBeanDefinition 中定義的一些常量和屬性,該類中還有一部分是操作這些屬性的 set 和 get 方法,這些方法都由子類來操作,且應用程序中真正使用的也是這些子類 BeanDefinition。
先來看 AbstractBeanDefinition 直接實現類:RootBeanDefinition、GenericBeanDefinition、ChildBeanDefinition。
RootBeanDefinition
該類繼承自 AbstractBeanDefinition,它可以單獨作為一個 BeanDefinition,也可以作為其他 BeanDefinition 的父類。
RootBeanDefinition 在 AbstractBeanDefinition 的基礎上定義了更多屬性。
public class RootBeanDefinition extends AbstractBeanDefinition {
// BeanDefinitionHolder 存儲 Bean 的名稱、別名、BeanDefinition
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通過它可以查看 Bean 的注解信息
private AnnotatedElement qualifiedElement;
// 允許緩存
boolean allowCaching = true;
// 工廠方法是否唯一
boolean isFactoryMethodUnique = false;
// 封裝了 java.lang.reflect.Type,提供了泛型相關的操作
volatile ResolvableType targetType;
// 緩存 Class,表示 RootBeanDefinition 存儲哪個類的信息
volatile Class<?> resolvedTargetType;
// 緩存工廠方法的返回類型
volatile ResolvableType factoryMethodReturnType;
// 這是以下四個構造方法字段的通用鎖
final Object constructorArgumentLock = new Object();
// 用於緩存已解析的構造方法或工廠方法
Executable resolvedConstructorOrFactoryMethod;
// 將構造方法參數標記為已解析
boolean constructorArgumentsResolved = false;
// 用於緩存完全解析的構造方法參數
Object[] resolvedConstructorArguments;
// 緩存待解析的構造方法參數
Object[] preparedConstructorArguments;
// 這是以下兩個后處理字段的通用鎖
final Object postProcessingLock = new Object();
// 表明是否被 MergedBeanDefinitionPostProcessor 處理過
boolean postProcessed = false;
// 在生成代理的時候會使用,表明是否已經生成代理
volatile Boolean beforeInstantiationResolved;
// 實際緩存的類型是 Constructor、Field、Method 類型
private Set<Member> externallyManagedConfigMembers;
// InitializingBean中 的 init 回調函數名 afterPropertiesSet 會在這里記錄,以便進行生命周期回調
private Set<String> externallyManagedInitMethods;
// DisposableBean 的 destroy 回調函數名 destroy 會在這里記錄,以便進生命周期回調
private Set<String> externallyManagedDestroyMethods;
...
}
ChildBeanDefinition
該類繼承自 AbstractBeanDefinition。其相當於一個子類,不可以單獨存在,必須依賴一個父 BeanDetintion,構造 ChildBeanDefinition 時,通過構造方法傳入父 BeanDetintion 的名稱或通過 setParentName 設置父名稱。它可以從父類繼承方法參數、屬性值,並可以重寫父類的方法,同時也可以增加新的屬性或者方法。若重新定義 init 方法,destroy 方法或者靜態工廠方法,ChildBeanDefinition 會重寫父類的設置。
從 Spring 2.5 開始,以編程方式注冊 Bean 定義的首選方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的絕大分部使用場合。
GenericBeanDefinition
GenericBeanDefinition 是 Spring 2.5 以后新引入的 BeanDefinition,是 ChildBeanDefinition 更好的替代者,它同樣可以通過 setParentName 方法設置父 BeanDefinition。
最后三個 BeanDefinition 既實現了 AnnotatedBeanDefinition 接口,又間接繼承 AbstractBeanDefinition 抽象類,這些 BeanDefinition 描述的都是注解形式的 Bean。
ConfigurationClassBeanDefinition
該類繼承自 RootBeanDefinition ,並實現了 AnnotatedBeanDefinition 接口。這個 BeanDefinition 用來描述在標注 @Configuration 注解的類中,通過 @Bean 注解實例化的 Bean。
其功能特點如下:
1、如果 @Bean 注解沒有指定 Bean 的名字,默認會用方法的名字命名 Bean。
2、標注 @Configuration 注解的類會成為一個工廠類,而標注 @Bean 注解的方法會成為工廠方法,通過工廠方法實例化 Bean,而不是直接通過構造方法初始化。
3、標注 @Bean 注解的類會使用構造方法自動裝配
AnnotatedGenericBeanDefinition
該類繼承自 GenericBeanDefinition ,並實現了 AnnotatedBeanDefinition 接口。這個 BeanDefinition 用來描述標注 @Configuration 注解的 Bean。
ScannedGenericBeanDefinition
該類繼承自 GenericBeanDefinition ,並實現了 AnnotatedBeanDefinition 接口。這個 BeanDefinition 用來描述標注 @Component 注解的 Bean,其派生注解如 @Service、@Controller 也同理。
總結
最后,我們來做個總結。BeanDefinition 主要是用來描述 Bean,其存儲了 Bean 的相關信息,Spring 實例化 Bean 時需讀取該 Bean 對應的 BeanDefinition。BeanDefinition 整體可以分為兩類,一類是描述通用的 Bean,還有一類是描述注解形式的 Bean。一般前者在 XML 時期定義 <bean‘> 標簽以及在 Spring 內部使用較多,而現今我們大都使用后者,通過注解形式加載 Bean。
以上就是本章內容,如果文章中有錯誤或者需要補充的請及時提出,本人感激不盡。
參考:
http://cmsblogs.com/?p=11731
https://cloud.tencent.com/developer/article/1497805