Spring Framework 源碼閱讀(二):BeanDefinition的作用
上一篇
Spring Framework
源碼閱讀部落格,部落客介紹了
Aware
接口及其實作類的作用,
Aware
的設計模式是模闆模式,而
BeanDefinition
的設計模式也是模闆模式,它們都基于某種職責定義了一個模闆,符合開閉原則,對擴充開放,對修改關閉,擴充在子類中實作。
- Spring Framework 源碼閱讀(一):Aware接口及其實作類的作用
- 設計模式-模闆模式(Template Pattern)
- 設計模式的七大原則
BeanDefinition
接口的定義
BeanDefinition
package org.springframework.beans.factory.config;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
/**
* A BeanDefinition describes a bean instance, which has property values,
* constructor argument values, and further information supplied by
* concrete implementations.
* * <p>This is just a minimal interface: The main intention is to allow a
* {@link BeanFactoryPostProcessor} to introspect and modify property values
* and other bean metadata.
* * @author Juergen Hoeller
* @author Rob Harrop
* @since 19.03.2004
* @see ConfigurableListableBeanFactory#getBeanDefinition
* @see org.springframework.beans.factory.support.RootBeanDefinition
* @see org.springframework.beans.factory.support.ChildBeanDefinition
*/
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
...
}
-
描述BeanDefinition
執行個體,比如bean
執行個體具有的屬性值、構造函數參數值以及由具體實作提供的進一步資訊。bean
- 主要目的是允許
檢查和修改屬性值以及其他BeanFactoryPostProcessor
中繼資料,bean
部落客以後會進行介紹,不然會涉及到很多其他知識,顯得雜亂無章,要盡量遵守單一職責原則。BeanFactoryPostProcessor
為什麼需要
BeanDefinition
?這就要讨論
Java
對象和
bean
有什麼不同,很顯然
bean
也是
Java
對象,但它擁有
Java
對象所沒有的功能,它可以在
Spring
容器中很容易實作自動注入、懶加載、多種作用域和根據各種限定條件進行初始化等,
Java
中的類可以描述該類執行個體的屬性和行為,是以
bean
也需要有描述它附加功能的定義,不然它隻是一個
Java
對象而已,這就是
BeanDefinition
的作用,從接口的命名也可看出來。
BeanDefinition
接口的方法和屬性:
屬性
-
:SCOPE_SINGLETON
的單例作用域,把bean
設定為單例作用域時,bean
容器隻會建立該Spring
的唯一執行個體。這個單一執行個體會被存儲到單例緩存(bean
)中,并且所有針對該singleton cache
的後續請求和引用都将傳回被緩存的對象執行個體。bean
-
:SCOPE_PROTOTYPE
的原型作用域,把bean
設定為原型作用域時,每次對bean
的請求(将其注入到另一個bean
中,或者以程式的方式調用容器的bean
方法)時getBean()
容器都會建立一個新的Spring
執行個體。bean
的其他作用域(bean
、request
、session
)需要在globalSession
環境中才能使用,以後部落客再進行詳細介紹。Web
-
:ROLE_APPLICATION
的角色訓示,訓示該bean
是應用程式的主要部分。通常對應于使用者定義的BeanDefinition
。bean
-
:ROLE_SUPPORT
的角色訓示,訓示該bean
是某些配置(通常是外部的BeanDefinition
)的支撐部分。ComponentDefinition
-
:ROLE_INFRASTRUCTURE
的角色訓示,訓示該bean
完全提供背景角色,與終端使用者無關。BeanDefinition
方法
-
、setParentName
:設定和擷取父getParentName
名稱的方法,為了描述BeanDefinition
之間的繼承關系,bean
也有父子關系,之後會介紹到合并BeanDefinition
的概念。BeanDefinition
-
、setBeanClassName
:設定和擷取getBeanClassName
的類名。bean
-
、setScope
:設定和擷取getScope
的作用域。bean
-
、setLazyInit
:設定isLazyInit
為懶加載、判斷bean
是否為懶加載。bean
-
、setDependsOn
:設定和擷取getDependsOn
所依賴的bean
的名稱數組(保證首先初始化這些bean
)。bean
-
、setAutowireCandidate
:isAutowireCandidate
表示AutowireCandidate
是否是自動注入到其他bean
的候選。僅影響基于類型(bean
)的自動注入。它不會影響按名稱(byType
)的顯式引用,即使指定的byName
未标記為bean
候選,也會解析為顯式引用。是以,如果名稱比對,會按名稱自動注入autowire
。bean
-
、setPrimary
:設定和判斷isPrimary
是否是自動注入到其他bean
的首選。bean
-
、setFactoryBeanName
:getFactoryBeanName
和FactoryBean
是不一樣的概念,BeanFactory
也是FactoryBean
,不過它可以用于建立某一類型的bean
(所有是一個bean
,也是一個factory
),是以借助bean
可以定制化建立FactoryBean
的過程。這兩個方法就是設定和擷取bean
的bean
(可以為FactoryBeanName
)。null
-
、setFactoryMethodName
:getFactoryMethodName
通過FactoryBean
來建立某一類型的FactoryMethod
。這兩個方法就是設定和擷取bean
的bean
(可以為FactoryMethod
)。null
-
、getConstructorArgumentValues
:擷取hasConstructorArgumentValues
的構造器參數值、判斷bean
是否有構造器參數值。bean
-
、getPropertyValues
:擷取要應用于hasPropertyValues
的新執行個體的屬性值、判斷是否有要應用于bean
的新執行個體的屬性值。bean
-
、setInitMethodName
:設定和擷取getInitMethodName
初始化方法的名稱。bean
-
、setDestroyMethodName
:設定和擷取getDestroyMethodName
銷毀方法的名稱。bean
-
、setRole
:設定和擷取getRole
的角色。bean
-
、setDescription
:設定和擷取getDescription
的BeanDefinition
(便于人類閱讀的描述)。human-readable description
-
:基于getResolvableType
或其他特定中繼資料,傳回該BeanDefinition
的可解析類型。這通常在運作時合并的BeanDefinition
(下面會進行介紹)上完全解析,但不一定在配置時定義的執行個體上完全解析。BeanDefinition
-
、isSingleton
:判斷isPrototype
是否是單例、原型bean
。bean
-
:判斷isAbstract
是否是bean
,如果是abstract
就不需要執行個體化了。abstract
-
:擷取getResourceDescription
來自的BeanDefinition
的描述(用于在出現錯誤時顯示上下文)。Resource
-
:傳回原始的getOriginatingBeanDefinition
,如果沒有,則傳回BeanDefinition
。null
BeanDefinition
接口還繼承了
AttributeAccessor
接口和
BeanMetadataElement
接口。
-
接口:定義了通用的接口,用于向任意對象附加中繼資料或從任意對象通路中繼資料。AttributeAccessor
-
接口:由攜帶配置源對象的BeanMetadataElement
中繼資料元素實作的接口。bean
使用這些定義來描述
bean
執行個體,而具體實作下放到子類中,比如
AbstractBeanDefinition
、
ChildBeanDefinition
、
RootBeanDefinition
以及
GenericBeanDefinition
,接下來部落客會詳細介紹它們的作用。
AbstractBeanDefinition
之前介紹過
BeanDefinition
的設計模式是模闆模式,
AbstractBeanDefinition
抽象類實作了
BeanDefinition
接口中的通用方法。
@SuppressWarnings("serial")
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
...
}
AbstractBeanDefinition
是具體、完備的
BeanDefinition
基類,并且分解出了
GenericBeanDefinition
、
RootBeanDefinition
和
ChildBeanDefinition
的公共屬性。
通用方法的實作:
/**
* 指定bean定義的bean類名
*/
@Override
public void setBeanClassName(@Nullable String beanClassName) {
this.beanClass = beanClassName;
}
/**
* 傳回bean定義的bean類名
*/
@Override
@Nullable
public String getBeanClassName() {
Object beanClassObject = this.beanClass;
if (beanClassObject instanceof Class) {
return ((Class<?>) beanClassObject).getName();
}
else {
return (String) beanClassObject;
}
}
/**
* 設定bean的作用域
*/
@Override
public void setScope(@Nullable String scope) {
this.scope = scope;
}
/**
* 傳回bean的作用域名稱
*/
@Override
@Nullable
public String getScope() {
return this.scope;
}
/**
* 是否是單例bean
*/
@Override
public boolean isSingleton() {
return SCOPE_SINGLETON.equals(this.scope) || SCOPE_DEFAULT.equals(this.scope);
}
/**
*是否是原型bean
*/
@Override
public boolean isPrototype() {
return SCOPE_PROTOTYPE.equals(this.scope);
}
/**
* 是否是abstract,如果是就不會進行執行個體化
*/
@Override
public boolean isAbstract() {
return this.abstractFlag;
}
/**
* 設定bean的加載方式為懶加載
*/
@Override
public void setLazyInit(boolean lazyInit) {
this.lazyInit = lazyInit;
}
/**
* 判斷bean是否設定懶加載
*/
@Override
public boolean isLazyInit() {
return (this.lazyInit != null && this.lazyInit.booleanValue());
}
...
也添加了新的屬性和方法,涉及到
autowire
(裝配
bean
的屬性):
/**
* 表示沒有自動裝配的常量
*/
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
/**
* 表示按名稱自動裝配bean屬性的常量
*/
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
/**
* 表示按類型自動裝配bean屬性的常量
*/
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
/**
* 表示通過構造函數自動裝配bean屬性的常量
*/
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
/**
* 表示通過bean類的内部檢測來确定适當的自動裝配政策的常量
*/
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
/**
* 設定自動裝配模式
*/
public void setAutowireMode(int autowireMode) {
this.autowireMode = autowireMode;
}
/**
* 傳回自動裝配模式
*/
public int getAutowireMode() {
return this.autowireMode;
}
/**
* 傳回已解析的自動裝配模式編碼
*/
public int getResolvedAutowireMode() {
if (this.autowireMode == AUTOWIRE_AUTODETECT) {
// 确定是應用setter自動裝配還是構造函數自動裝配
// 如果它有一個無參數構造函數,則被視為setter自動裝配
// 否則将嘗試構造函數自動裝配
Constructor<?>[] constructors = getBeanClass().getConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.getParameterCount() == 0) {
return AUTOWIRE_BY_TYPE;
}
}
return AUTOWIRE_CONSTRUCTOR;
}
else {
return this.autowireMode;
}
}
...
涉及到
dependency check
(依賴項檢查):
/**
* 表示沒有依賴項檢查的常量
*/
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;
...
/**
* 設定依賴項檢查的編碼,就是上面的0、1、2以及3
*/
public void setDependencyCheck(int dependencyCheck) {
this.dependencyCheck = dependencyCheck;
}
/**
* 傳回目前依賴項檢查的編碼
*/
public int getDependencyCheck() {
return this.dependencyCheck;
}
涉及到
qualifier
(限定符):
/**
* 注冊一個用于autowire候選解析的限定符。
*/
public void addQualifier(AutowireCandidateQualifier qualifier) {
this.qualifiers.put(qualifier.getTypeName(), qualifier);
}
/**
* 傳回bean是否具有指定的限定符
*/
public boolean hasQualifier(String typeName) {
return this.qualifiers.containsKey(typeName);
}
/**
* 傳回映射到提供的類型名稱的限定符
*/
@Nullable
public AutowireCandidateQualifier getQualifier(String typeName) {
return this.qualifiers.get(typeName);
}
/**
* 傳回所有的限定符。
*/
public Set<AutowireCandidateQualifier> getQualifiers() {
return new LinkedHashSet<>(this.qualifiers.values());
}
/**
* 将限定符從提供的AbstractBeanDefinition複制到此AbstractBeanDefinition
*/
public void copyQualifiersFrom(AbstractBeanDefinition source) {
Assert.notNull(source, "Source must not be null");
this.qualifiers.putAll(source.qualifiers);
}
這些都是
AbstractBeanDefinition
中新增加的内容(基于特定業務的抽象),當然這些還不是
AbstractBeanDefinition
的全貌,大家可以自己去探索一下。接下來會介紹
AbstractBeanDefinition
三個比較重要的子類
ChildBeanDefinition
、
RootBeanDefinition
以及
GenericBeanDefinition
。
ChildBeanDefinition
子
Bean
(繼承了父
Bean
)的
BeanDefinition
。子
BeanDefinition
對父
BeanDefinition
有固定的依賴關系。
子
BeanDefinition
将從父
BeanDefinition
繼承構造函數參數值、屬性值和方法重寫,并具有添加新值的選項。如果指定了
init method
、
destroy method
或
static factory method
,它們将覆寫相應父
BeanDefinition
的設定。其餘設定将始終取自子
BeanDefinition
:
depends on
、
autowire mode
、
dependency check
、
singleton
以及
lazy init
。
自
Spring2.5
以來,以程式設計方式注冊
BeanDefinition
的首選方法是
GenericBeanDefinition
類,它允許通過
setParentName
方法動态定義父依賴項。對于大多數用例,這有效地取代了
ChildBeanDefinition
類。是以這裡不會詳細地介紹
ChildBeanDefinition
,它的源碼也比較短,大家可以自己去看看。
RootBeanDefinition
RootBeanDefinition
表示在運作時支援
Spring BeanFactory
中特定
bean
的合并
BeanDefinition
。它可能是從互相繼承的多個原始
BeanDefinition
建立的(通常注冊為
GenericBeanDefinition
)。
RootBeanDefinition
本質上是運作時的統一
BeanDefinition
視圖。
RootBeanDefinition
也可用于在配置階段注冊單個
BeanDefinition
。然而,自
Spring2.5
以來,以程式設計方式注冊
BeanDefinition
的首選方法是
GenericBeanDefinition
類。
GenericBeanDefinition
的優點是它允許動态定義父依賴項,而不是将角色寫死(
hard-coding
)為
RootBeanDefinition
。
GenericBeanDefinition
GenericBeanDefinition
是标準
BeanDefinition
的一站式服務。與任何
BeanDefinition
一樣,它允許指定類以及可選的構造函數參數值和屬性值。可以靈活地配置
parentName
屬性,以便從父
BeanDefinition
中進行派生。通常,使用
GenericBeanDefinition
類注冊使用者可見的
BeanDefinition
。在父子關系恰好是預先确定的情況下,使用
RootBeanDefinition
和
ChildBeanDefinition
。
代碼也很短:
建立module
先在
Spring Framework
源碼中增加一個
application module
,這在之前的博文中已經介紹過了,這裡就不再贅述:
- 編譯 Spring Framework 5.2.17源碼 & 在源碼中使用 ApplicationContext 擷取定義的Bean
IMessageService
接口:
package com.kaven.service;
/**
* @Author: ITKaven
* @Date: 2021/09/25 14:04
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/
public interface IMessageService {
String getMessage();
}
MessageServiceImpl
實作類:
package com.kaven.service.impl;
import com.kaven.service.IMessageService;
import org.springframework.stereotype.Service;
/**
* @Author: ITKaven
* @Date: 2021/09/25 14:05
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/
@Service("message")
public class MessageServiceImpl implements IMessageService {
@Override
public String getMessage() {
return "Hello Kaven";
}
}
Application
啟動類:
package com.kaven;
import com.kaven.service.IMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @Author: ITKaven
* @Date: 2021/09/25 13:54
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/
@ComponentScan({"com.kaven"})
public class Application {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);
IMessageService messageServiceBean = (IMessageService) applicationContext.getBean("message");
System.out.println(messageServiceBean.getMessage());
Test test = (Test) applicationContext.getBean("test");
System.out.println("message bean: " + (test.messageService == messageServiceBean));
Test test2 = (Test) applicationContext.getBean("test");
System.out.println("message bean: " + (test2.messageService == messageServiceBean));
System.out.println("test bean: " + (test == test2));
System.out.println(applicationContext.getBeanDefinitionCount());
Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);
}
@Component("test")
@Scope("prototype")
static class Test {
@Autowired
private IMessageService messageService;
}
}
運作輸出:
> Task :application:Application.main()
Hello Kaven
message bean: true
message bean: true
test bean: false
7
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
application
test
message
BUILD SUCCESSFUL in 19s
61 actionable tasks: 2 executed, 59 up-to-date
源碼分析 - 注冊 BeanDefinition
BeanDefinition
上下文中有
7
個
BeanDefinition
,而
test bean
被擷取了兩次,為什麼沒有兩個
test BeanDefinition
?因為每個
BeanDefinition
描述了一類
bean
,并且
BeanDefinition
是根據
beanName
擷取的,
BeanDefinition
類似于類(對象定義),而
bean
類似于對象,是以
beanName
就類似于
className
,類描述了該類所有對象的行為和屬性,
BeanDefinition
也是如此。從輸出結果上來看,
bean
預設是單例(除非使用
@Scope
注解改變其作用域),其實在
AbstractBeanDefinition
的源碼中也可以發現作用域的預設值。
@SuppressWarnings("serial")
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
/**
* 預設作用域名稱的常量:"",等同于單例狀态(會被替換為單例,在相關源碼的注釋中有解釋)
*/
public static final String SCOPE_DEFAULT = "";
@Nullable
private String scope = SCOPE_DEFAULT;
...
}
AbstractBeanDefinition
的源碼中還有一些比較常見配置的預設值,比如
bean
預設不是
abstract
的(是以需要被執行個體化)、
lazyInit
為
null
(是以不會被懶加載)、沒有自動裝配、依賴項檢查為
DEPENDENCY_CHECK_NONE
(沒有依賴項檢查)、是自動注入的候選
bean
和不是首選
bean
(
primary
):
private boolean abstractFlag = false;
@Nullable
private Boolean lazyInit;
private int autowireMode = AUTOWIRE_NO;
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
private boolean autowireCandidate = true;
private boolean primary = false;
很顯然下面這
4
個
BeanDefinition
是
Spring
定義的:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
它們在
AnnotationConfigUtils
抽象類的
registerAnnotationConfigProcessors
方法中出現:
public abstract class AnnotationConfigUtils {
/**
* 内部管理Configuration注解的處理器的bean名稱
*/
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
/**
* 内部管理Autowired注解的處理器的bean名稱
*/
public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
/**
* 内部管理JSR-250注解的處理器的bean名稱
*/
public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalCommonAnnotationProcessor";
/**
* 内部管理JPA注解的處理器的bean名稱
*/
public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
/**
* 内部管理EventListener注解的處理器的bean名稱
*/
public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
"org.springframework.context.event.internalEventListenerProcessor";
/**
* 内部管理EventListenerFactory的bean名稱
*/
public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
"org.springframework.context.event.internalEventListenerFactory";
/**
* 在給定registry中注冊所有相關的注解post processors
* @param registry 要在其上操作的registry
* @param source 觸發此注冊的配置源元素(已提取),可能為null
* @return Set<BeanDefinitionHolder>,其中包含此調用實際注冊的所有BeanDefinition
*/
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
...
}
其實這個
BeanDefinitionRegistry registry
參數就是部落客在
Application
類中建立的
AnnotationConfigApplicationContext
執行個體。并且這裡定義的
BeanDefinition
是
RootBeanDefinition
執行個體(
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
,部落客在後面會進行讨論)。
AnnotationConfigApplicationContext
類的父類
GenericApplicationContext
實作了
BeanDefinitionRegistry
接口。
下一步調用了
AnnotationConfigUtils
抽象類的的
registerPostProcessor
方法(可以看見
role
設定為
ROLE_INFRASTRUCTURE
):
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
之後又調用了
GenericApplicationContext
類的
registerBeanDefinition
方法,很顯然是
AnnotationConfigApplicationContext
類繼承了父類
GenericApplicationContext
的
registerBeanDefinition
方法。
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
GenericApplicationContext
類的
beanFactory
屬性是
DefaultListableBeanFactory
類的執行個體。
private final DefaultListableBeanFactory beanFactory;
DefaultListableBeanFactory
類是
Spring
預設實作的
ConfigurableListableBeanFactory
和
BeanDefinitionRegistry
接口:一個基于
bean definition
中繼資料的成熟
bean factory
。
先不糾結這些類的作用,類太多了,無法把所有類的作用和原理都了解的一清二楚,需要關注的是
DefaultListableBeanFactory
類中的
beanDefinitionMap
和
beanDefinitionNames
屬性,很顯然它們存儲了
beanName
以及相關
BeanDefinition
執行個體的資訊。
/** BeanDefinition對象的映射,bean名稱為key */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** 按注冊順序列出BeanDefinition名稱 */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
下一步調用了
DefaultListableBeanFactory
類中的
registerBeanDefinition
方法,在該方法中,将
beanName
和
beanDefinition
資訊存儲到了
beanDefinitionMap
和
beanDefinitionNames
屬性中:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
這
4
個内置
bean
的
BeanDefinition
就完成了注冊。
為什麼會注冊這些内置
bean
?可以看一下調用鍊:
先是在
main
方法中調用了
AnnotationConfigApplicationContext
類的構造函數:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
又接着調用了
AnnotationConfigApplicationContext
類的無參構造函數:
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
然後連續調用了
AnnotatedBeanDefinitionReader
類的兩個構造函數:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
從這裡就開始注冊内置
bean
的
BeanDefinition
了。
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
接着會注冊
application bean
的
BeanDefinition
,調用鍊如下圖所示:
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
在調用鍊的
doRegisterBean
方法中可以發現
application bean
的
BeanDefinition
是
AnnotatedGenericBeanDefinition
(
GenericBeanDefinition
的子類)執行個體,明顯和内置
bean
的
RootBeanDefinition
執行個體不一樣。
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
可以回顧一下部落客對
RootBeanDefinition
的介紹:
RootBeanDefinition
表示在運作時支援
Spring BeanFactory
中特定
bean
的合并
BeanDefinition
。
RootBeanDefinition
本質上是運作時的統一
BeanDefinition
視圖。
RootBeanDefinition
也可用于在配置階段注冊單個
BeanDefinition
。然而,自
Spring2.5
以來,以程式設計方式注冊
BeanDefinition
的首選方法是
GenericBeanDefinition
類。
部落客的了解:因為内置
bean
沒有父
bean
,繼承關系是明确的,是以内置
bean
的
BeanDefinition
也不會有父
BeanDefinition
,也就不需要進行合并
BeanDefinition
的操作,此時的
BeanDefinition
就是内置
bean
的統一
BeanDefinition
視圖,是以可以直接是
RootBeanDefinition
執行個體。
而
application bean
是使用者自定義的
bean
,繼承關系并不明确,是有可能存在繼承關系的,是以有可能需要進行合并
BeanDefinition
的操作,此時的
BeanDefinition
就不一定是
application bean
的統一
BeanDefinition
視圖,是以定義為
AnnotatedGenericBeanDefinition
執行個體,以便之後可以進行合并
BeanDefinition
的操作(通過設定
parentName
)。而什麼時候會進行合并
BeanDefinition
的操作,下面會進行介紹。
test
以及
message bean
的
BeanDefinition
都是在如下圖所示的調用鍊中被定義:
現在所有
bean
的
BeanDefinition
都被注冊了,下面介紹合并
BeanDefinition
。
源碼分析 - 合并 BeanDefinition
BeanDefinition
合并
BeanDefinition
的操作,在
bean
需要執行個體化之前會被執行,如
AbstractBeanFactory
抽象類的
doGetBean
方法(删除了不相關的代碼):
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
}
接着調用了
AbstractBeanFactory
抽象類的
getMergedLocalBeanDefinition
方法:
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
AbstractBeanFactory
抽象類的
mergedBeanDefinitions
屬性是一個
ConcurrentHashMap
執行個體,存儲了以
bean
名稱為
key
,合并的
RootBeanDefinition
為
value
的鍵值對。
/** 從bean名稱映射到合并的RootBeanDefinition */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
RootBeanDefinition
類中的
stale
屬性,使用
volatile
修飾符修飾,保證了可見性。
/** 确定是否需要重新合并BeanDefinition */
volatile boolean stale;
如果之前沒有合并過,或者需要重新合并,就會調用
AbstractBeanFactory
抽象類的
getMergedBeanDefinition
方法,而先會調用
DefaultListableBeanFactory
類的
getBeanDefinition
方法擷取
beanName
對應的
BeanDefinition
:
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (logger.isTraceEnabled()) {
logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
通過源碼,其實可以發現該
this
(
DefaultListableBeanFactory
執行個體)就是之前說的在
main
方法中建立的
AnnotationConfigApplicationContext
執行個體的
beanFactory
屬性。
在調用
AbstractApplicationContext
類的
refresh
方法時,将
AnnotationConfigApplicationContext
執行個體的
beanFactory
屬性傳進去了(删除了部分代碼):
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
}
}
是以調用
DefaultListableBeanFactory
類的
getBeanDefinition
方法就是擷取之前定義的
BeanDefinition
(通過
beanName
,内置
bean
對應
RootBeanDefinition
執行個體,而自定義
bean
對應
GenericBeanDefinition
執行個體)。
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
擷取
beanName
對應的
BeanDefinition
後,傳回到
AbstractBeanFactory
抽象類的
getMergedBeanDefinition
方法(方法命名相同,和之前不是一樣的方法):
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
又繼續調用
AbstractBeanFactory
抽象類的
getMergedBeanDefinition
方法(方法命名相同,和之前不是一樣的方法):
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
// 合并BeanDefinition時需要上鎖,避免發生線程安全問題
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
// 沒有合并過或者需要重新合并BeanDefinition
if (mbd == null || mbd.stale) {
previous = mbd;
// 沒有父BeanDefinition,不需要合并,将原有的BeanDefinition拷貝即可
if (bd.getParentName() == null) {
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
// 非RootBeanDefinition執行個體,可能是GenericBeanDefinition類或其子類的執行個體
else {
mbd = new RootBeanDefinition(bd);
}
}
// 有父BeanDefinition,需要合并
else {
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
// 合并父BeanDefinition
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
// 合并父BeanDefinition
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// 将合并的父BeanDefinition轉換成RootBeanDefinition執行個體
mbd = new RootBeanDefinition(pbd);
// 子BeanDefinition重寫合并的父BeanDefinition得到合并的子BeanDefinition
mbd.overrideFrom(bd);
}
// 作用域為""時(預設),會被替代為SCOPE_SINGLETON(單例),和上面說的對應起來了
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// 非單例bean中包含的bean本身不能是單例bean
// 更正這個問題,因為這可能是外部bean的父子合并,在這種情況下,原始内部BeanDefinition将不會繼承合并的外部bean的單例狀态。
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// 暫時緩存合并的BeanDefinition
// 以後可能會重新合并,以擷取中繼資料更改
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
可見合并的
BeanDefinition
預設就是
RootBeanDefinition
執行個體,這也就是為什麼說
RootBeanDefinition
本質上是運作時的統一
BeanDefinition
視圖的原因了。該方法通過遞歸調用的形式合并
BeanDefinition
,這也符合
bean
之間的繼承關系圖。