SmartInstantiationAwareBeanPostProcessor
一、基本信息
?? 作者 - Lex ?? 博客 - 我的CSDN ?? 文章目錄 - 所有文章 ?? 源碼地址 - SmartInstantiationAwareBeanPostProcessor源碼
二、接口描述
InstantiationAwareBeanPostProcessor。接口,能夠?qū)?Spring 容器創(chuàng)建的 beans 進(jìn)行更精細(xì)的控制和更多的干預(yù),尤其是在涉及代理和其他高級(jí)場(chǎng)景時(shí)。
三、接口源碼
SmartInstantiationAwareBeanPostProcessor 是 Spring 框架自 2.0.3 版本開始引入的一個(gè)核心接口,主要用于框架內(nèi)部。正常情況下我們實(shí)現(xiàn)BeanPostProcessor接口或者InstantiationAwareBeanPostProcessorAdapter接口就能滿足自定義需求。
/**
* InstantiationAwareBeanPostProcessor 接口的擴(kuò)展,
* 增加了預(yù)測(cè)處理的bean的最終類型的回調(diào)方法。
*
* 注意: 這是一個(gè)特定目的的接口,主要用于
* 框架內(nèi)部。一般來(lái)說(shuō),應(yīng)用程序提供的后處理器應(yīng)該
* 直接實(shí)現(xiàn)簡(jiǎn)單的 BeanPostProcessor
* 接口或繼承 InstantiationAwareBeanPostProcessorAdapter 類。
* 即使在點(diǎn)版本中,也可能向此接口添加新方法。
*
* @author Juergen Hoeller
* @since 2.0.3
* @see InstantiationAwareBeanPostProcessorAdapter
*/
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
/**
* 預(yù)測(cè)從此處理器的 #postProcessBeforeInstantiation 回調(diào)返回的bean的類型。
* 默認(rèn)實(shí)現(xiàn)返回 null。
* @param beanClass bean的原始類
* @param beanName bean的名稱
* @return bean的類型,如果不可預(yù)測(cè)則為 null
* @throws org.springframework.beans.BeansException 出錯(cuò)時(shí)拋出
*/
@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 確定給定bean的候選構(gòu)造函數(shù)。
* 默認(rèn)實(shí)現(xiàn)返回 null。
* @param beanClass bean的原始類(永遠(yuǎn)不是 null)
* @param beanName bean的名稱
* @return 候選構(gòu)造函數(shù),如果沒(méi)有指定則為 null
* @throws org.springframework.beans.BeansException 出錯(cuò)時(shí)拋出
*/
@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
throws BeansException {
return null;
}
/**
* 為了解決循環(huán)引用,提前獲取指定bean的引用。
* 此回調(diào)為后處理器提供了一個(gè)機(jī)會(huì),可以在目標(biāo)bean實(shí)例完全初始化之前暴露一個(gè)包裝器。
* 暴露的對(duì)象應(yīng)當(dāng)?shù)韧?#postProcessBeforeInitialization /
* #postProcessAfterInitialization 否則會(huì)暴露。需要注意的是,
* 由此方法返回的對(duì)象將被用作bean引用,除非后處理器從上述后處理回調(diào)中返回一個(gè)不同的包裝器。
* 默認(rèn)實(shí)現(xiàn)返回給定的 bean 原樣。
* @param bean 原始bean實(shí)例
* @param beanName bean的名稱
* @return 作為bean引用暴露的對(duì)象(通常使用傳入的bean實(shí)例作為默認(rèn)值)
* @throws org.springframework.beans.BeansException 出錯(cuò)時(shí)拋出
*/
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
}
四、主要功能
-
預(yù)測(cè) Bean 類型 (predictBeanType)
- 這個(gè)方法允許在實(shí)例化 bean 之前預(yù)測(cè) bean 的最終類型。這在涉及代理或其他類型轉(zhuǎn)換的場(chǎng)景中特別有用,例如,一個(gè) bean 可能會(huì)被一個(gè) AOP 代理包裹,此方法可以返回預(yù)期的代理類型而不是實(shí)際的目標(biāo)類型,這有助于 Spring 在創(chuàng)建和連接 bean 時(shí)做出更加明智的決策,特別是在涉及類型匹配(如自動(dòng)裝配)時(shí)。
-
確定候選構(gòu)造函數(shù) (determineCandidateConstructors)
- 在 bean 實(shí)例化之前,這個(gè)方法允許確定用于給定 bean 的構(gòu)造函數(shù),這為我們提供了一種方式來(lái)定制或干預(yù) Spring 默認(rèn)的構(gòu)造函數(shù)選擇邏輯,例如,當(dāng)存在多個(gè)構(gòu)造函數(shù)并且我們想基于特定邏輯選擇其中一個(gè)時(shí)。
-
獲取早期 Bean 引用 (getEarlyBeanReference)
- 這個(gè)方法提供了一個(gè)機(jī)會(huì),允許在 bean 完全初始化之前暴露一個(gè)包裝器或代理,它在處理循環(huán)依賴時(shí)特別有用,當(dāng)一個(gè) bean 還未完全初始化但另一個(gè) bean 需要引用它時(shí),這個(gè)方法就會(huì)被調(diào)用,這樣,我們可以暴露一個(gè)早期的 bean 引用,可能是一個(gè)代理,這個(gè)代理在完成所有初始化步驟后仍然有效。
五、最佳實(shí)踐
首先來(lái)看看啟動(dòng)類入口,上下文環(huán)境使用AnnotationConfigApplicationContext(此類是使用Java注解來(lái)配置Spring容器的方式),構(gòu)造參數(shù)我們給定了一個(gè)MyConfiguration組件類。
public class SmartInstantiationAwareBeanPostProcessorApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
}
}
這里使用@Bean注解,定義了一個(gè)Bean,是為了確保 MySmartInstantiationAwareBeanPostProcessor 被 Spring 容器執(zhí)行
@Configuration
@ComponentScan("com.xcs.spring")
public class MyConfiguration {
@Bean
public static MySmartInstantiationAwareBeanPostProcessor mySmartInstantiationAwareBeanPostProcessor(){
return new MySmartInstantiationAwareBeanPostProcessor();
}
}
自定義的 SmartInstantiationAwareBeanPostProcessor 實(shí)現(xiàn),然后我們重寫了 determineCandidateConstructors 方法。如果類中有一個(gè)或多個(gè)帶有 @MyAutowired 注解的構(gòu)造函數(shù),這些構(gòu)造函數(shù)將被作為候選返回,如果沒(méi)有找到任何帶有 @MyAutowired 注解的構(gòu)造函數(shù),那么后處理器會(huì)嘗試查找默認(rèn)(無(wú)參數(shù))的構(gòu)造函數(shù),如果沒(méi)有找到帶有 @MyAutowired 注解的構(gòu)造函數(shù),并且沒(méi)有默認(rèn)構(gòu)造函數(shù),那么所有可用的構(gòu)造函數(shù)將被作為候選返回,從而使 Spring 能夠選擇最具體的構(gòu)造函數(shù)。
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
// 首先,查找@MyAutowired帶注釋的構(gòu)造函數(shù)
List<Constructor<?>> myAutowiredConstructors = Arrays.stream(beanClass.getConstructors())
.filter(constructor -> constructor.isAnnotationPresent(MyAutowired.class))
.collect(Collectors.toList());
if (!myAutowiredConstructors.isEmpty()) {
return myAutowiredConstructors.toArray(new Constructor<?>[0]);
}
// 其次,檢查默認(rèn)構(gòu)造函數(shù)
try {
Constructor<?> defaultConstructor = beanClass.getDeclaredConstructor();
return new Constructor<?>[]{defaultConstructor};
} catch (NoSuchMethodException e) {
// 找不到默認(rèn)構(gòu)造函數(shù),請(qǐng)繼續(xù)選擇合適的構(gòu)造函數(shù)
}
// 返回所有構(gòu)造函數(shù),讓Spring將選擇最具體的構(gòu)造函數(shù)
return beanClass.getConstructors();
}
}
自定義注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
public @interface MyAutowired {
}
兩個(gè)普通Bean對(duì)象
@Component
public class MyServiceA {
public void execute() {
System.out.println("MyServiceA executed");
}
}
@Component
public class MyServiceB {
public void execute() {
System.out.println("MyServiceB executed");
}
}
我們定義了四個(gè)構(gòu)造函數(shù)(默認(rèn)構(gòu)造函數(shù),只接受 MyServiceA 的構(gòu)造函數(shù),只接受 MyServiceB 的構(gòu)造函數(shù),同時(shí)接受 MyServiceA 和 MyServiceB 的構(gòu)造函數(shù))。根據(jù)MySmartInstantiationAwareBeanPostProcessor定義的分析下面選擇構(gòu)造函數(shù)過(guò)程,當(dāng) Spring 容器嘗試實(shí)例化 MyService 類的一個(gè)實(shí)例時(shí),由于存在一個(gè)被 @MyAutowired 標(biāo)記的構(gòu)造函數(shù),所以它將首先嘗試使用它。這意味著如果在 Spring 容器中已經(jīng)有了 MyServiceA 和 MyServiceB 的 bean,那么這兩者都會(huì)被注入,并且會(huì)輸出 "Constructor with ServiceA and ServiceB used"。如果沒(méi)有提供 @MyAutowired 或者沒(méi)有適當(dāng)?shù)?bean 來(lái)滿足帶有 @MyAutowired 注解的構(gòu)造函數(shù)的依賴關(guān)系,則會(huì)嘗試使用默認(rèn)構(gòu)造函數(shù)。如果沒(méi)有默認(rèn)構(gòu)造函數(shù),Spring 將嘗試其他構(gòu)造函數(shù)并查找可以匹配的 bean。在這種情況下,如果 MyServiceA 和 MyServiceB 都可用,Spring 將選擇接受最多參數(shù)的構(gòu)造函數(shù),因?yàn)檫@被視為最具體的構(gòu)造函數(shù)。
@Component
public class MyService {
private final MyServiceA myServiceA;
private final MyServiceB myServiceB;
public MyService() {
System.out.println("Default constructor used");
this.myServiceA = null;
this.myServiceB = null;
}
public MyService(MyServiceA myServiceA) {
System.out.println("Constructor with ServiceA used");
this.myServiceA = myServiceA;
this.myServiceB = null;
}
public MyService(MyServiceB serviceB) {
System.out.println("Constructor with ServiceB used");
this.myServiceA = null;
this.myServiceB = serviceB;
}
@MyAutowired
public MyService(MyServiceA serviceA, MyServiceB serviceB) {
System.out.println("Constructor with ServiceA and ServiceB used");
this.myServiceA = serviceA;
this.myServiceB = serviceB;
}
}
運(yùn)行結(jié)果發(fā)現(xiàn),Spring 容器成功地使用帶有 @MyAutowired 注解的構(gòu)造函數(shù)實(shí)例化了 MyService 類,并正確地注入了它的兩個(gè)依賴:MyServiceA 和 MyServiceB。
Constructor with ServiceA and ServiceB used
<span style="color:red">注意:由于predictBeanType,getEarlyBeanReference方法是Spring框架內(nèi)部使用無(wú)法演示出效果,因此不演示這兩個(gè)方法。</span>
六、時(shí)序圖
sequenceDiagram
Title: SmartInstantiationAwareBeanPostProcessor時(shí)序圖
participant SmartInstantiationAwareBeanPostProcessorApplication
participant AnnotationConfigApplicationContext
participant AbstractApplicationContext
participant DefaultListableBeanFactory
participant AbstractBeanFactory
participant DefaultSingletonBeanRegistry
participant AbstractAutowireCapableBeanFactory
participant MySmartInstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessorApplication->>AnnotationConfigApplicationContext:AnnotationConfigApplicationContext(componentClasses)<br>創(chuàng)建上下文
AnnotationConfigApplicationContext->>AbstractApplicationContext:refresh()<br>刷新上下文
AbstractApplicationContext->>AbstractApplicationContext:finishBeanFactoryInitialization(beanFactory)<br>初始化Bean工廠
AbstractApplicationContext->>DefaultListableBeanFactory:preInstantiateSingletons()<br>實(shí)例化單例
DefaultListableBeanFactory->>AbstractBeanFactory:getBean(name)<br>獲取Bean
AbstractBeanFactory->>AbstractBeanFactory:doGetBean(name,requiredType,args,typeCheckOnly)<br>執(zhí)行獲取Bean
AbstractBeanFactory->>DefaultSingletonBeanRegistry:getSingleton(beanName,singletonFactory)<br>獲取單例Bean
DefaultSingletonBeanRegistry-->>AbstractBeanFactory:getObject()<br>獲取Bean實(shí)例
AbstractBeanFactory->>AbstractAutowireCapableBeanFactory:createBean(beanName,mbd,args)<br>創(chuàng)建Bean
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:doCreateBean(beanName,mbd,args)<br>執(zhí)行Bean創(chuàng)建
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:createBeanInstance(beanName,mbd,args)<br>創(chuàng)建bean實(shí)例
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:determineConstructorsFromBeanPostProcessors(beanClass, beanName)<br>確定構(gòu)造方法
AbstractAutowireCapableBeanFactory->>MySmartInstantiationAwareBeanPostProcessor:determineCandidateConstructors(beanClass, beanName)<br>回調(diào)候選構(gòu)造方法
MySmartInstantiationAwareBeanPostProcessor-->>AbstractAutowireCapableBeanFactory:返回構(gòu)造方法
AbstractAutowireCapableBeanFactory-->>AbstractBeanFactory:返回Bean對(duì)象
AbstractBeanFactory-->>DefaultListableBeanFactory:返回Bean對(duì)象
AnnotationConfigApplicationContext-->>SmartInstantiationAwareBeanPostProcessorApplication:初始化完成
七、源碼分析
首先來(lái)看看啟動(dòng)類入口,上下文環(huán)境使用AnnotationConfigApplicationContext(此類是使用Java注解來(lái)配置Spring容器的方式),構(gòu)造參數(shù)我們給定了一個(gè)MyConfiguration組件類。
<span style="color:red">PS:由于predictBeanType, determineCandidateConstructors, 和 getEarlyBeanReference 這三個(gè)方法雖然都屬于 SmartInstantiationAwareBeanPostProcessor 接口,但它們處理不同的關(guān)注點(diǎn),具有不同的目的。在進(jìn)行源碼分析時(shí),此處只演示determineCandidateConstructors方法。</span>
public class SmartInstantiationAwareBeanPostProcessorApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
}
}
在org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext構(gòu)造函數(shù)中,執(zhí)行了三個(gè)步驟,我們重點(diǎn)關(guān)注refresh()方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
在org.springframework.context.support.AbstractApplicationContext#refresh方法中,我們重點(diǎn)關(guān)注一下finishBeanFactoryInitialization(beanFactory)這方法會(huì)對(duì)實(shí)例化所有剩余非懶加載的單列Bean對(duì)象,其他方法不是本次源碼閱讀的重點(diǎn)暫時(shí)忽略。
@Override
public void refresh() throws BeansException, IllegalStateException {
// ... [代碼部分省略以簡(jiǎn)化]
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// ... [代碼部分省略以簡(jiǎn)化]
}
在org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization方法中,會(huì)繼續(xù)調(diào)用DefaultListableBeanFactory類中的preInstantiateSingletons方法來(lái)完成所有剩余非懶加載的單列Bean對(duì)象。
/**
* 完成此工廠的bean初始化,實(shí)例化所有剩余的非延遲初始化單例bean。
*
* @param beanFactory 要初始化的bean工廠
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ... [代碼部分省略以簡(jiǎn)化]
// 完成所有剩余非懶加載的單列Bean對(duì)象。
beanFactory.preInstantiateSingletons();
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons方法中,主要的核心目的是預(yù)先實(shí)例化所有非懶加載的單例bean。在Spring的上下文初始化完成后,該方法會(huì)被觸發(fā),以確保所有單例bean都被正確地創(chuàng)建并初始化。其中getBean(beanName)是此方法的核心操作。對(duì)于容器中定義的每一個(gè)單例bean,它都會(huì)調(diào)用getBean方法,這將觸發(fā)bean的實(shí)例化、初始化及其依賴的注入。如果bean之前沒(méi)有被創(chuàng)建過(guò),那么這個(gè)調(diào)用會(huì)導(dǎo)致其被實(shí)例化和初始化。
public void preInstantiateSingletons() throws BeansException {
// ... [代碼部分省略以簡(jiǎn)化]
// 循環(huán)遍歷所有bean的名稱
for (String beanName : beanNames) {
getBean(beanName);
}
// ... [代碼部分省略以簡(jiǎn)化]
}
在org.springframework.beans.factory.support.AbstractBeanFactory#getBean()方法中,又調(diào)用了doGetBean方法來(lái)實(shí)際執(zhí)行創(chuàng)建Bean的過(guò)程,傳遞給它bean的名稱和一些其他默認(rèn)的參數(shù)值。此處,doGetBean負(fù)責(zé)大部分工作,如查找bean定義、創(chuàng)建bean(如果尚未創(chuàng)建)、處理依賴關(guān)系等。
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
在org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法中,首先檢查所請(qǐng)求的bean是否是一個(gè)單例并且已經(jīng)創(chuàng)建。如果尚未創(chuàng)建,它將創(chuàng)建一個(gè)新的實(shí)例。在這個(gè)過(guò)程中,它處理可能的異常情況,如循環(huán)引用,并確保返回的bean是正確的類型。這是Spring容器bean生命周期管理的核心部分。
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// ... [代碼部分省略以簡(jiǎn)化]
// 開始創(chuàng)建bean實(shí)例
if (mbd.isSingleton()) {
// 如果bean是單例的,我們會(huì)嘗試從單例緩存中獲取它
// 如果不存在,則使用lambda創(chuàng)建一個(gè)新的實(shí)例
sharedInstance = getSingleton(beanName, () -> {
try {
// 嘗試創(chuàng)建bean實(shí)例
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ... [代碼部分省略以簡(jiǎn)化]
}
});
// 對(duì)于某些bean(例如FactoryBeans),可能需要進(jìn)一步處理以獲取真正的bean實(shí)例
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// ... [代碼部分省略以簡(jiǎn)化]
// 確保返回的bean實(shí)例與請(qǐng)求的類型匹配
return adaptBeanInstance(name, beanInstance, requiredType);
}
在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton()方法中,主要負(fù)責(zé)從單例緩存中獲取一個(gè)已存在的bean實(shí)例,或者使用提供的ObjectFactory創(chuàng)建一個(gè)新的實(shí)例。這是確保bean在Spring容器中作為單例存在的關(guān)鍵部分。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 斷言bean名稱不能為空
Assert.notNull(beanName, "Bean name must not be null");
// 同步訪問(wèn)單例對(duì)象緩存,確保線程安全
synchronized (this.singletonObjects) {
// 從緩存中獲取單例對(duì)象
Object singletonObject = this.singletonObjects.get(beanName);
// 如果緩存中沒(méi)有找到
if (singletonObject == null) {
// ... [代碼部分省略以簡(jiǎn)化]
try {
// 使用工廠創(chuàng)建新的單例實(shí)例
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// ... [代碼部分省略以簡(jiǎn)化]
}
catch (BeanCreationException ex) {
// ... [代碼部分省略以簡(jiǎn)化]
}
finally {
// ... [代碼部分省略以簡(jiǎn)化]
}
// ... [代碼部分省略以簡(jiǎn)化]
}
// 返回單例對(duì)象
return singletonObject;
}
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()方法中,主要的邏輯是調(diào)用 doCreateBean,這是真正進(jìn)行 bean 實(shí)例化、屬性填充和初始化的地方。這個(gè)方法會(huì)返回新創(chuàng)建的 bean 實(shí)例。
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ... [代碼部分省略以簡(jiǎn)化]
try {
// 正常的bean實(shí)例化、屬性注入和初始化。
// 這里是真正進(jìn)行bean創(chuàng)建的部分。
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
// 記錄bean成功創(chuàng)建的日志
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// ... [代碼部分省略以簡(jiǎn)化]
}
catch (Throwable ex) {
// ... [代碼部分省略以簡(jiǎn)化]
}
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法中,如果是單例,嘗試從工廠實(shí)例緩存中獲取。如果緩存中沒(méi)有實(shí)例,創(chuàng)建一個(gè)新的實(shí)例。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 實(shí)例化 bean。
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 如果是單例,嘗試從工廠實(shí)例緩存中獲取。
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 如果緩存中沒(méi)有實(shí)例,創(chuàng)建一個(gè)新的實(shí)例。
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// ... [省略部分代碼以簡(jiǎn)化]
// 返回創(chuàng)建和初始化后的 bean。
return exposedObject;
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance方法中,首先嘗試從 SmartInstantiationAwareBeanPostProcessor 中確定用于 bean 的構(gòu)造函數(shù),接下來(lái),它檢查是否已經(jīng)確定了某些構(gòu)造函數(shù)、是否 bean 定義指明了使用構(gòu)造函數(shù)自動(dòng)裝配、是否為 bean 提供了構(gòu)造函數(shù)參數(shù)值或是否有明確的構(gòu)造函數(shù)參數(shù)。如果滿足這些條件之一,它將調(diào)用 autowireConstructor 方法,這個(gè)方法會(huì)使用確定的構(gòu)造函數(shù)(或者選擇一個(gè))來(lái)實(shí)例化 bean。接著,如果之前沒(méi)有選擇構(gòu)造函數(shù),它會(huì)檢查是否存在首選的默認(rèn)構(gòu)造函數(shù)。這些構(gòu)造函數(shù)可以是由用戶明確指定的或是由其他部分的框架預(yù)先確定的。如果有這樣的構(gòu)造函數(shù),框架又會(huì)嘗試使用 autowireConstructor 方法,最后,如果所有先前的步驟都沒(méi)有返回構(gòu)造函數(shù),spring會(huì)默認(rèn)為 bean 使用無(wú)參數(shù)構(gòu)造函數(shù)。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// ... [省略部分代碼以簡(jiǎn)化]
// 是否有用于自動(dòng)裝配的候選構(gòu)造函數(shù)?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 如果從后處理器中確定了構(gòu)造函數(shù)、或者 bean 定義信息指明了使用構(gòu)造函數(shù)自動(dòng)裝配、或者存在構(gòu)造函數(shù)參數(shù)值、或者提供了特定的構(gòu)造函數(shù)參數(shù)
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 使用確定的構(gòu)造函數(shù)進(jìn)行自動(dòng)裝配
return autowireConstructor(beanName, mbd, ctors, args);
}
// 是否有優(yōu)先使用的默認(rèn)構(gòu)造函數(shù)?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 使用優(yōu)選的構(gòu)造函數(shù)進(jìn)行自動(dòng)裝配
return autowireConstructor(beanName, mbd, ctors, null);
}
// 沒(méi)有特殊處理:直接使用無(wú)參數(shù)構(gòu)造函數(shù)進(jìn)行實(shí)例化
return instantiateBean(beanName, mbd);
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors方法中,回調(diào)每一個(gè) SmartInstantiationAwareBeanPostProcessor,調(diào)用它的 determineCandidateConstructors 方法以確定 bean 的構(gòu)造函數(shù)。如果找到了候選的構(gòu)造函數(shù),就返回這些構(gòu)造函數(shù)。如果多個(gè) SmartInstantiationAwareBeanPostProcessor 都返回了構(gòu)造函數(shù),則只會(huì)使用第一個(gè)返回的構(gòu)造函數(shù)。
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
return null;
}
最后執(zhí)行到我們自定義的邏輯中,在我們自定義的邏輯中,如果類中有一個(gè)或多個(gè)帶有 @MyAutowired 注解的構(gòu)造函數(shù),這些構(gòu)造函數(shù)將被作為候選返回,如果沒(méi)有找到任何帶有 @MyAutowired 注解的構(gòu)造函數(shù),那么后處理器會(huì)嘗試查找默認(rèn)(無(wú)參數(shù))的構(gòu)造函數(shù),如果沒(méi)有找到帶有 @MyAutowired 注解的構(gòu)造函數(shù),并且沒(méi)有默認(rèn)構(gòu)造函數(shù),那么所有可用的構(gòu)造函數(shù)將被作為候選返回,從而使 Spring 能夠選擇最具體的構(gòu)造函數(shù)。
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
// 首先,查找@MyAutowired帶注釋的構(gòu)造函數(shù)
List<Constructor<?>> myAutowiredConstructors = Arrays.stream(beanClass.getConstructors())
.filter(constructor -> constructor.isAnnotationPresent(MyAutowired.class))
.collect(Collectors.toList());
if (!myAutowiredConstructors.isEmpty()) {
return myAutowiredConstructors.toArray(new Constructor<?>[0]);
}
// 其次,檢查默認(rèn)構(gòu)造函數(shù)
try {
Constructor<?> defaultConstructor = beanClass.getDeclaredConstructor();
return new Constructor<?>[]{defaultConstructor};
} catch (NoSuchMethodException e) {
// 找不到默認(rèn)構(gòu)造函數(shù),請(qǐng)繼續(xù)選擇合適的構(gòu)造函數(shù)
}
// 返回所有構(gòu)造函數(shù),讓Spring將選擇最具體的構(gòu)造函數(shù)
return beanClass.getConstructors();
}
}
八、注意事項(xiàng)
-
性能影響
- 每個(gè)
SmartInstantiationAwareBeanPostProcessor,都會(huì)對(duì)每個(gè) bean 的創(chuàng)建過(guò)程產(chǎn)生額外的開銷。因此,應(yīng)避免創(chuàng)建不必要的SmartInstantiationAwareBeanPostProcessor,并確保其實(shí)現(xiàn)盡可能高效。
- 每個(gè)
-
與其他后處理器的交互
- 如果有多個(gè)
SmartInstantiationAwareBeanPostProcessor,它們會(huì)按照注冊(cè)的順序被調(diào)用。應(yīng)確保這些后處理器的執(zhí)行順序是正確的,避免意外的覆蓋或沖突,因?yàn)橹粫?huì)使用第一個(gè)返回的構(gòu)造函數(shù)。
- 如果有多個(gè)
-
返回非空值的考慮
-
determineCandidateConstructors:當(dāng)這個(gè)方法返回非空值時(shí),Spring 容器將不會(huì)再嘗試使用其他方式自動(dòng)選擇構(gòu)造函數(shù),predictBeanType:返回的類型應(yīng)該盡可能準(zhǔn)確地反映后處理器預(yù)期的最終 bean 類型,以確保類型匹配和自動(dòng)裝配的正確性。
-
-
與
InstantiationAwareBeanPostProcessor的區(qū)別- 雖然
SmartInstantiationAwareBeanPostProcessor擴(kuò)展了InstantiationAwareBeanPostProcessor,但它添加了更多的回調(diào)和復(fù)雜性。除非我們確實(shí)需要這些額外的功能,否則最好僅使用InstantiationAwareBeanPostProcessor。
- 雖然
九、總結(jié)
最佳實(shí)踐總結(jié)
-
初始化 Spring 容器
- 通過(guò)
AnnotationConfigApplicationContext初始化 Spring 容器,并使用MyConfiguration作為配置類。
- 通過(guò)
-
注冊(cè)后處理器
- 在
MyConfiguration中,我們注冊(cè)了自定義的SmartInstantiationAwareBeanPostProcessor實(shí)現(xiàn)MySmartInstantiationAwareBeanPostProcessor。這確保了它會(huì)在 Spring 容器中被考慮并執(zhí)行。
- 在
-
自定義后處理器的工作
- 我們的
MySmartInstantiationAwareBeanPostProcessor重寫了determineCandidateConstructors方法,該方法的目標(biāo)是返回一組構(gòu)造函數(shù),供 Spring 選擇用于 bean 的實(shí)例化。
- 我們的
-
查找
@MyAutowired- 首先,后處理器會(huì)查找?guī)в?
@MyAutowired注解的構(gòu)造函數(shù)。
- 首先,后處理器會(huì)查找?guī)в?
-
使用默認(rèn)構(gòu)造函數(shù)
- 如果沒(méi)有帶有
@MyAutowired的構(gòu)造函數(shù),后處理器會(huì)查找默認(rèn)構(gòu)造函數(shù)。
- 如果沒(méi)有帶有
-
返回所有構(gòu)造函數(shù)
- 如果沒(méi)有找到上述兩種情況的構(gòu)造函數(shù),所有的構(gòu)造函數(shù)將被作為候選返回。
-
Bean 的實(shí)例化
- 當(dāng) Spring 嘗試實(shí)例化
MyServicebean 時(shí),它會(huì)使用MySmartInstantiationAwareBeanPostProcessor中指定的構(gòu)造函數(shù)。在這個(gè)示例中,由于我們有一個(gè)帶有@MyAutowired注解的構(gòu)造函數(shù),且兩個(gè)依賴MyServiceA和MyServiceB都可用,這個(gè)構(gòu)造函數(shù)被選擇并使用,從而輸出了"Constructor with ServiceA and ServiceB used"。
- 當(dāng) Spring 嘗試實(shí)例化
-
關(guān)于其他方法
- 雖然
SmartInstantiationAwareBeanPostProcessor提供了其他方法,如predictBeanType和getEarlyBeanReference,但這些主要是為 Spring 內(nèi)部使用。在大多數(shù)常規(guī)用例中,我們可能不需要重寫或使用它們。
- 雖然
源碼分析總結(jié)
-
啟動(dòng)和初始化:
使用
AnnotationConfigApplicationContext初始化Spring上下文。構(gòu)造參數(shù)中給定一個(gè)配置類,該配置類中定義了自定義的
SmartInstantiationAwareBeanPostProcessor。
-
Bean預(yù)實(shí)例化過(guò)程:
在上下文刷新過(guò)程中,
finishBeanFactoryInitialization方法會(huì)預(yù)實(shí)例化所有非懶加載的單例Bean。preInstantiateSingletons方法循環(huán)遍歷所有bean的名稱并通過(guò)getBean方法實(shí)例化bean。如果Bean已經(jīng)存在并且是單例,則會(huì)從單例緩存中返回。否則,會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。
-
Bean創(chuàng)建過(guò)程:
創(chuàng)建Bean的核心邏輯在
doCreateBean方法中。如果bean是單例并且在緩存中不存在,則會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。在創(chuàng)建bean實(shí)例時(shí),首先從
SmartInstantiationAwareBeanPostProcessor中確定用于bean的構(gòu)造函數(shù)。這個(gè)過(guò)程首先嘗試使用帶有特定注解(如我們的示例中的
@MyAutowired)的構(gòu)造函數(shù)。如果沒(méi)有這樣的構(gòu)造函數(shù),則會(huì)選擇默認(rèn)構(gòu)造函數(shù)。
如果沒(méi)有帶有注解的構(gòu)造函數(shù)且沒(méi)有默認(rèn)構(gòu)造函數(shù),則會(huì)返回所有可用的構(gòu)造函數(shù),從而使Spring選擇最具體的構(gòu)造函數(shù)。
-
自定義的邏輯:
自定義的
SmartInstantiationAwareBeanPostProcessor實(shí)現(xiàn)首先檢查是否有帶有@MyAutowired注解的構(gòu)造函數(shù)。如果有,則這些構(gòu)造函數(shù)會(huì)作為候選返回。
如果沒(méi)有,則后處理器會(huì)檢查是否存在默認(rèn)的無(wú)參數(shù)構(gòu)造函數(shù)。
如果既沒(méi)有帶有
@MyAutowired注解的構(gòu)造函數(shù),也沒(méi)有默認(rèn)構(gòu)造函數(shù),則所有構(gòu)造函數(shù)將被作為候選返回。