Spring核心容器之BeanDefinition解析
前言
現(xiàn)如今,我們一般獲取對象的方式有兩種,一種是手動(dòng)直接 new;另一種是交給 Spring 管理,Spring 將管理的對象稱之為 Bean,容器會(huì)先實(shí)例化 Bean,然后自動(dòng)注入,實(shí)例化的過程就需要依賴 BeanDefinition。
BeanDefinition 用于保存 Bean 的相關(guān)信息,包括屬性、構(gòu)造方法參數(shù)、依賴的 Bean 名稱及是否單例、延遲加載等,它是實(shí)例化 Bean 的原材料,Spring 就是根據(jù) BeanDefinition 中的信息實(shí)例化 Bean。
BeanDefinition的繼承體系
BeanDefinition 是一個(gè)接口,它有多個(gè)實(shí)現(xiàn)類,這些實(shí)現(xiàn)類分別描述不同類型的 Bean。
BeanDefinition
一個(gè) BeanDefinition 描述了一個(gè) Bean 實(shí)例,實(shí)例包含屬性值、構(gòu)造方法參數(shù)值以及更多實(shí)現(xiàn)信息。該 BeanDefinition 只是是一個(gè)最小的接口,主要目的是允許修改屬性值和其他 Bean 元數(shù)據(jù),這里列出幾個(gè)核心方法。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { // 單例、原型標(biāo)識(shí)符 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; // 標(biāo)識(shí) Bean 的類別,分別對應(yīng) 用戶定義的 Bean、來源于配置文件的 Bean、Spring 內(nèi)部的 Bean int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; // 設(shè)置、返回 Bean 的父類名稱 void setParentName(@Nullable String parentName); String getParentName(); // 設(shè)置、返回 Bean 的 className void setBeanClassName(@Nullable String beanClassName); String getBeanClassName(); // 設(shè)置、返回 Bean 的作用域 void setScope(@Nullable String scope); String getScope(); // 設(shè)置、返回 Bean 是否懶加載 void setLazyInit(boolean lazyInit); boolean isLazyInit(); // 設(shè)置、返回當(dāng)前 Bean 所依賴的其它 Bean 名稱。 void setDependsOn(@Nullable String... dependsOn); String[] getDependsOn(); // 設(shè)置、返回 Bean 是否可以自動(dòng)注入。只對 @Autowired 注解有效 void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); // 設(shè)置、返回當(dāng)前 Bean 是否為主要候選 Bean 。 // 當(dāng)同一個(gè)接口有多個(gè)實(shí)現(xiàn)類時(shí),通過該屬性來配置某個(gè) Bean 為主候選 Bean。 void setPrimary(boolean primary); boolean isPrimary(); // 設(shè)置、返回創(chuàng)建該 Bean 的工廠類。 void setFactoryBeanName(@Nullable String factoryBeanName); String getFactoryBeanName(); // 設(shè)置、返回創(chuàng)建該 Bean 的工廠方法 void setFactoryMethodName(@Nullable String factoryMethodName); String getFactoryMethodName(); // 返回該 Bean 構(gòu)造方法參數(shù)值、所有屬性 ConstructorArgumentValues getConstructorArgumentValues(); MutablePropertyValues getPropertyValues(); // 返回該 Bean 是否是單例、是否是非單例、是否是抽象的 boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); // 返回 Bean 的類別。類別對應(yīng)上面的三個(gè)屬性值。 int getRole(); ... }
可以看到 BeanDefinition 接口提供了一系列操作 Bean 元數(shù)據(jù)的set、get方法,這些操作為 Bean 的描述定義了一套模板,具體的實(shí)現(xiàn)則交由子類。
AnnotatedBeanDefinition
AnnotatedBeanDefinition 是 BeanDefinition 子接口之一,該接口擴(kuò)展了 BeanDefinition 的功能,其用來操作注解元數(shù)據(jù)。一般情況下,通過注解方式得到的 Bean(@Component、@Bean),其 BeanDefinition 類型都是該接口的實(shí)現(xiàn)類。
public interface AnnotatedBeanDefinition extends BeanDefinition { // 獲得當(dāng)前 Bean 的注解元數(shù)據(jù) AnnotationMetadata getMetadata(); // 獲得當(dāng)前 Bean 的工廠方法上的元數(shù)據(jù) MethodMetadata getFactoryMethodMetadata(); }
該接口可以返回兩個(gè)元數(shù)據(jù)的類:
- AnnotationMetadata:主要對 Bean 的注解信息進(jìn)行操作,如:獲取當(dāng)前 Bean 標(biāo)注的所有注解、判斷是否包含指定注解。
- MethodMetadata:方法的元數(shù)據(jù)類。提供獲取方法名稱、此方法所屬類的全類名、是否是抽象方法、判斷是否是靜態(tài)方法、判斷是否是final方法等。
AbstractBeanDefinition
AbstractBeanDefinition 是 BeanDefinition 的子抽象類,也是其他 BeanDefinition 類型的基類,其實(shí)現(xiàn)了接口中定義的一系列操作方法,并定義了一系列的常量屬性,這些常量會(huì)直接影響到 Spring 實(shí)例化 Bean 時(shí)的策略。核心屬性如下。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { // 默認(rèn)的 SCOPE,默認(rèn)是單例 public static final String SCOPE_DEFAULT = ""; // 不進(jìn)行自動(dòng)裝配 public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; // 根據(jù) Bean 的名字進(jìn)行自動(dòng)裝配,byName public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; // 根據(jù) Bean 的類型進(jìn)行自動(dòng)裝配,byType public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; // 根據(jù)構(gòu)造器進(jìn)行自動(dòng)裝配 public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; // 首先嘗試按構(gòu)造器自動(dòng)裝配。如果失敗,再嘗試使用 byType 進(jìn)行自動(dòng)裝配。(Spring 3.0 之后已廢除) public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT; // 通過依賴檢查來查看 Bean 的每個(gè)屬性是否都設(shè)置完成 // 以下常量分別對應(yīng):不檢查、對依賴對象檢查、對基本類型,字符串和集合進(jìn)行檢查、對全部屬性進(jìn)行檢查 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; // 關(guān)閉應(yīng)用上下文時(shí)需調(diào)用的方法名稱 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; // 默認(rèn)不自動(dòng)裝配 private int autowireMode = AUTOWIRE_NO; // 默認(rèn)不依賴檢查 private int dependencyCheck = DEPENDENCY_CHECK_NONE; // 依賴的 Bean 列表 private String[] dependsOn; // 可以作為自動(dòng)裝配的候選者,意味著可以自動(dòng)裝配到其他 Bean 的某個(gè)屬性中 private boolean autowireCandidate = true; // 創(chuàng)建當(dāng)前 Bean 實(shí)例工廠類名稱 private String factoryBeanName; // 創(chuàng)建當(dāng)前 Bean 實(shí)例工廠類中方法名稱 private String factoryMethodName; // 存儲(chǔ)構(gòu)造方法的參數(shù) private ConstructorArgumentValues constructorArgumentValues; // 存儲(chǔ) Bean 屬性名稱以及對應(yīng)的值 private MutablePropertyValues propertyValues; // 存儲(chǔ)被覆蓋的方法信息 private MethodOverrides methodOverrides; // init、destroy 方法名稱 private String initMethodName; private String destroyMethodName; // 是否執(zhí)行 init 和 destroy 方法 private boolean enforceInitMethod = true; private boolean enforceDestroyMethod = true; // Bean 是否是用戶定義的而不是應(yīng)用程序本身定義的 private boolean synthetic = false; // Bean 的身份類別,默認(rèn)是用戶定義的 Bean private int role = BeanDefinition.ROLE_APPLICATION; // Bean 的描述信息 private String description; // Bean 定義的資源 private Resource resource; ... }
以上是 AbstractBeanDefinition 中定義的一些常量和屬性,該類中還有一部分是操作這些屬性的 set 和 get 方法,這些方法都由子類來操作,且應(yīng)用程序中真正使用的也是這些子類 BeanDefinition。
先來看 AbstractBeanDefinition 直接實(shí)現(xiàn)類:RootBeanDefinition、GenericBeanDefinition、ChildBeanDefinition。
RootBeanDefinition
該類繼承自 AbstractBeanDefinition,它可以單獨(dú)作為一個(gè) BeanDefinition,也可以作為其他 BeanDefinition 的父類。
RootBeanDefinition 在 AbstractBeanDefinition 的基礎(chǔ)上定義了更多屬性。
public class RootBeanDefinition extends AbstractBeanDefinition { // BeanDefinitionHolder 存儲(chǔ) Bean 的名稱、別名、BeanDefinition private BeanDefinitionHolder decoratedDefinition; // AnnotatedElement 是java反射包的接口,通過它可以查看 Bean 的注解信息 private AnnotatedElement qualifiedElement; // 允許緩存 boolean allowCaching = true; // 工廠方法是否唯一 boolean isFactoryMethodUnique = false; // 封裝了 java.lang.reflect.Type,提供了泛型相關(guān)的操作 volatile ResolvableType targetType; // 緩存 Class,表示 RootBeanDefinition 存儲(chǔ)哪個(gè)類的信息 volatile Class<?> resolvedTargetType; // 緩存工廠方法的返回類型 volatile ResolvableType factoryMethodReturnType; // 這是以下四個(gè)構(gòu)造方法字段的通用鎖 final Object constructorArgumentLock = new Object(); // 用于緩存已解析的構(gòu)造方法或工廠方法 Executable resolvedConstructorOrFactoryMethod; // 將構(gòu)造方法參數(shù)標(biāo)記為已解析 boolean constructorArgumentsResolved = false; // 用于緩存完全解析的構(gòu)造方法參數(shù) Object[] resolvedConstructorArguments; // 緩存待解析的構(gòu)造方法參數(shù) Object[] preparedConstructorArguments; // 這是以下兩個(gè)后處理字段的通用鎖 final Object postProcessingLock = new Object(); // 表明是否被 MergedBeanDefinitionPostProcessor 處理過 boolean postProcessed = false; // 在生成代理的時(shí)候會(huì)使用,表明是否已經(jīng)生成代理 volatile Boolean beforeInstantiationResolved; // 實(shí)際緩存的類型是 Constructor、Field、Method 類型 private Set<Member> externallyManagedConfigMembers; // InitializingBean中 的 init 回調(diào)函數(shù)名 afterPropertiesSet 會(huì)在這里記錄,以便進(jìn)行生命周期回調(diào) private Set<String> externallyManagedInitMethods; // DisposableBean 的 destroy 回調(diào)函數(shù)名 destroy 會(huì)在這里記錄,以便進(jìn)生命周期回調(diào) private Set<String> externallyManagedDestroyMethods; ... }
ChildBeanDefinition
該類繼承自 AbstractBeanDefinition。其相當(dāng)于一個(gè)子類,不可以單獨(dú)存在,必須依賴一個(gè)父 BeanDetintion,構(gòu)造 ChildBeanDefinition 時(shí),通過構(gòu)造方法傳入父 BeanDetintion 的名稱或通過 setParentName 設(shè)置父名稱。它可以從父類繼承方法參數(shù)、屬性值,并可以重寫父類的方法,同時(shí)也可以增加新的屬性或者方法。若重新定義 init 方法,destroy 方法或者靜態(tài)工廠方法,ChildBeanDefinition 會(huì)重寫父類的設(shè)置。
從 Spring 2.5 開始,以編程方式注冊 Bean 定義的首選方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的絕大分部使用場合。
GenericBeanDefinition
GenericBeanDefinition 是 Spring 2.5 以后新引入的 BeanDefinition,是 ChildBeanDefinition 更好的替代者,它同樣可以通過 setParentName 方法設(shè)置父 BeanDefinition。
最后三個(gè) BeanDefinition 既實(shí)現(xiàn)了 AnnotatedBeanDefinition 接口,又間接繼承 AbstractBeanDefinition 抽象類,這些 BeanDefinition 描述的都是注解形式的 Bean。
ConfigurationClassBeanDefinition
該類繼承自 RootBeanDefinition ,并實(shí)現(xiàn)了 AnnotatedBeanDefinition 接口。這個(gè) BeanDefinition 用來描述在標(biāo)注 @Configuration 注解的類中,通過 @Bean 注解實(shí)例化的 Bean。
其功能特點(diǎn)如下:
1、如果 @Bean 注解沒有指定 Bean 的名字,默認(rèn)會(huì)用方法的名字命名 Bean。
2、標(biāo)注 @Configuration 注解的類會(huì)成為一個(gè)工廠類,而標(biāo)注 @Bean 注解的方法會(huì)成為工廠方法,通過工廠方法實(shí)例化 Bean,而不是直接通過構(gòu)造方法初始化。
3、標(biāo)注 @Bean 注解的類會(huì)使用構(gòu)造方法自動(dòng)裝配
AnnotatedGenericBeanDefinition
該類繼承自 GenericBeanDefinition ,并實(shí)現(xiàn)了 AnnotatedBeanDefinition 接口。這個(gè) BeanDefinition 用來描述標(biāo)注 @Configuration 注解的 Bean。
ScannedGenericBeanDefinition
該類繼承自 GenericBeanDefinition ,并實(shí)現(xiàn)了 AnnotatedBeanDefinition 接口。這個(gè) BeanDefinition 用來描述標(biāo)注 @Component 注解的 Bean,其派生注解如 @Service、@Controller 也同理。
總結(jié)
最后,我們來做個(gè)總結(jié)。BeanDefinition 主要是用來描述 Bean,其存儲(chǔ)了 Bean 的相關(guān)信息,Spring 實(shí)例化 Bean 時(shí)需讀取該 Bean 對應(yīng)的 BeanDefinition。
BeanDefinition 整體可以分為兩類,一類是描述通用的 Bean,還有一類是描述注解形式的 Bean。
一般前者在 XML 時(shí)期定義 <bean’> 標(biāo)簽以及在 Spring 內(nèi)部使用較多,而現(xiàn)今我們大都使用后者,通過注解形式加載 Bean。
到此這篇關(guān)于Spring核心容器之BeanDefinition解析的文章就介紹到這了,更多相關(guān)Spring的BeanDefinition解析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)相同屬性名稱及相似類型的pojo、dto、vo等互轉(zhuǎn)操作
這篇文章主要介紹了java實(shí)現(xiàn)相同屬性名稱及相似類型的pojo、dto、vo等互轉(zhuǎn)操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08SpringBoot下使用MyBatis-Puls代碼生成器的方法
這篇文章主要介紹了SpringBoot下使用MyBatis-Puls代碼生成器的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10詳解Java項(xiàng)目中讀取properties文件
本篇文章主要介紹了Java項(xiàng)目中讀取properties文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2016-12-12Java BigDecimal解決double精度丟失的問題
我們在日常開發(fā)中, 有很多時(shí)候會(huì)遇到小數(shù)(double類型)精確計(jì)算,本文主要介紹了Java BigDecimal解決double精度丟失的問題,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11解決SpringMVC @RequestMapping不設(shè)置value出現(xiàn)的問題
這篇文章主要介紹了解決SpringMVC @RequestMapping不設(shè)置value出現(xiàn)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java基于棧方式解決漢諾塔問題實(shí)例【遞歸與非遞歸算法】
這篇文章主要介紹了Java基于棧方式解決漢諾塔問題的方法,結(jié)合實(shí)例形式分析了java棧方式采用遞歸與非遞歸算法解決漢諾塔問題的相關(guān)操作技巧,需要的朋友可以參考下2017-11-11java實(shí)現(xiàn)根據(jù)ip地址獲取地理位置
本文給大家匯總介紹了2種分別使用新浪和淘寶接口,實(shí)現(xiàn)根據(jù)IP地址獲取詳細(xì)的地理位置的代碼,非常的實(shí)用,有需要的小伙伴可以參考下。2016-03-03