Spring(四)核心容器 - BeanDefinition 解析

前言

在上篇文章中,咱們討論了 refresh 的前四個方法,主要是對 ApplicationContext 上下文啓動作一些準備工做。原計劃是對接下來的 invokeBeanFactoryPostProcessors 方法進行討論,但該方法涉及 Spring 中一個很是重要的概念: BeanDefinition,因此,這裏先對 BeanDefinition 進行討論,這樣也有利於完善 Spring 的知識體系。java

注:本篇文章使用的 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。ide

image

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 的描述定義了一套模板,具體的實現則交由子類。post

AnnotatedBeanDefinition

AnnotatedBeanDefinition 是 BeanDefinition 子接口之一,該接口擴展了 BeanDefinition 的功能,其用來操做註解元數據。通常狀況下,經過註解方式獲得的 Bean(@Component、@Bean),其 BeanDefinition 類型都是該接口的實現類。spa

public interface AnnotatedBeanDefinition extends BeanDefinition {

    // 得到當前 Bean 的註解元數據
    AnnotationMetadata getMetadata();

    // 得到當前 Bean 的工廠方法上的元數據
    MethodMetadata getFactoryMethodMetadata();
}

該接口能夠返回兩個元數據的類:代理

  • AnnotationMetadata:主要對 Bean 的註解信息進行操做,如:獲取當前 Bean 標註的全部註解、判斷是否包含指定註解。
  • MethodMetadata:方法的元數據類。提供獲取方法名稱、此方法所屬類的全類名、是不是抽象方法、判斷是不是靜態方法、判斷是不是final方法等。

AbstractBeanDefinition

AbstractBeanDefinition 是 BeanDefinition 的子抽象類,也是其餘 BeanDefinition 類型的基類,其實現了接口中定義的一系列操做方法,並定義了一系列的常量屬性,這些常量會直接影響到 Spring 實例化 Bean 時的策略。核心屬性以下。code

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。

其功能特色以下:

一、若是 @Bean 註解沒有指定 Bean 的名字,默認會用方法的名字命名 Bean。

二、標註 @Configuration 註解的類會成爲一個工廠類,而標註 @Bean 註解的方法會成爲工廠方法,經過工廠方法實例化 Bean,而不是直接經過構造方法初始化。

三、標註 @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/dev...

相關文章
相關標籤/搜索