1. 程式人生 > 其它 >Spring原始碼1-BeanDefinition 解析

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。