Spring原始碼1-BeanDefinition 解析
前言
Spring容器 中一個非常重要的概念: BeanDefinition
注:本文springboot、spring版本如下圖
Spring容器的強大之處:獲取物件時,不需要我們手工主動new物件,完全交給Spring容器管理。
Spring 將管理的物件稱之為 Bean,容器會先例項化 Bean,然後自動注入,例項化的過程就需要依賴 BeanDefinition。
BeanDefinition 用於儲存 Bean 的相關資訊,包括屬性、構造方法引數、依賴的 Bean 名稱及是否單例、延遲載入等,它是例項化 Bean 的原材料,Spring 就是根據 BeanDefinition 中的資訊例項化 Bean。
BeanDefinition物件詳解
BeanDefinition是一個介面類,實現類以及子介面很多,如下:
BeanDefinition 用於儲存 Bean 的相關資訊,包括屬性、構造方法引數、依賴的 Bean 名稱及是否單例、延遲載入等,詳細核心內容如下:
/**
BeanDefinition描述了一個bean例項,它有屬性值,
建構函式引數值,以及提供的進一步資訊
具體實現。
這只是一個最小的介面:主要目的是允許一個
{@link BeanFactoryPostProcessor}來自省和修改屬性值
和其他bean元資料。
* @see ConfigurableListableBeanFactory#getBeanDefinition *@see org.springframework.beans.factory.support.RootBeanDefinition * @see org.springframework.beans.factory.support.ChildBeanDefinition */ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { /** * 標準單例、原型模式識別符號 * @see #setScope * @see ConfigurableBeanFactory#SCOPE_SINGLETON*/ String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; /** * 標識Bean的類別 0-使用者定義的Bean 1-來源於配置檔案的Bean 2-Spring內部的Bean*/ int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; // Modifiable attributes /** * 設定、返回父類名稱 */ void setParentName(@Nullable String parentName); String getParentName(); /** * 設定、返回 className * @see #setParentName * @see #setFactoryBeanName * @see #setFactoryMethodName */ void setBeanClassName(@Nullable String beanClassName); String getBeanClassName(); /** * 設定、返回作用域 * @see #SCOPE_SINGLETON * @see #SCOPE_PROTOTYPE */ void setScope(@Nullable String scope); String getScope(); /** * 設定、返回 是否懶載入*/ void setLazyInit(boolean lazyInit); boolean isLazyInit(); /** * 設定、返回當前Bean物件所依賴的其他Bean名稱 */ void setDependsOn(@Nullable String... dependsOn); String[] getDependsOn(); /** *設定、返回是否可以自動注入,對應@Autowired 註解 */ void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); /** * 設定、返回當前Bean 是否為主要候選Bean 一個介面多個例項物件,可以通過此屬性來設定指定具體例項物件*/ void setPrimary(boolean primary); boolean isPrimary(); /** * 設定、返回Bean的工長類*/ void setFactoryBeanName(@Nullable String factoryBeanName); String getFactoryBeanName(); /** * 工廠方法 * @see #setFactoryBeanName * @see #setBeanClassName */ void setFactoryMethodName(@Nullable String factoryMethodName); String getFactoryMethodName(); /** *返回構造引數值、屬性值*/ ConstructorArgumentValues getConstructorArgumentValues(); default boolean hasConstructorArgumentValues() { return !getConstructorArgumentValues().isEmpty(); } MutablePropertyValues getPropertyValues(); default boolean hasPropertyValues() { return !getPropertyValues().isEmpty(); } /** * 初始化方法名稱*/ void setInitMethodName(@Nullable String initMethodName); String getInitMethodName(); /** * 銷燬方法的名稱*/ void setDestroyMethodName(@Nullable String destroyMethodName); String getDestroyMethodName(); /** * Bean的類別 * @see #ROLE_APPLICATION * @see #ROLE_SUPPORT * @see #ROLE_INFRASTRUCTURE */ void setRole(int role); int getRole(); ........ 此處省略其他原始碼 }
AnnotatedBeanDefinition
AnnotatedBeanDefinition 是 BeanDefinition 子介面之一,該介面擴充套件了 BeanDefinition 的功能,其用來操作註解元資料。一般情況下,通過註解方式得到的 Bean(@Component、@Bean)。
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。