一文詳解Spring構(gòu)造函數(shù)推斷
正文
Spring 提供了一組基本的功能,例如依賴注入(DI)和面向切面編程(AOP)。其中一個(gè)非常強(qiáng)大的功能是構(gòu)造函數(shù)自動(dòng)注入,也稱為構(gòu)造函數(shù)推斷。在本文中,我們將深入探討Spring構(gòu)造函數(shù)推斷的底層原理,并解釋Spring是如何實(shí)現(xiàn)它的。
自動(dòng)注入
構(gòu)造函數(shù)自動(dòng)注入是指 Spring 自動(dòng)解析 bean 的構(gòu)造函數(shù)參數(shù),并將它們傳遞給相應(yīng)的構(gòu)造函數(shù)。這樣,我們就不必顯式地在XML或Java配置文件中指定每個(gè) bean 的構(gòu)造函數(shù)參數(shù)。這是一個(gè)非常方便的功能,特別是在有許多 bean 需要注入的情況下。
底層原理
Spring 使用 Java 反射機(jī)制來(lái)執(zhí)行構(gòu)造函數(shù)推斷。當(dāng) Spring 需要實(shí)例化一個(gè) bean 時(shí),它將首先使用 Java 反射機(jī)制檢查該 bean 的構(gòu)造函數(shù)。
然后,它將檢查每個(gè)構(gòu)造函數(shù)的參數(shù)類型,并嘗試在 Spring 應(yīng)用程序上下文中查找與參數(shù)類型匹配的 bean。
如果找到匹配的 bean,則 Spring 將使用該 bean 實(shí)例化構(gòu)造函數(shù)參數(shù)。如果找不到匹配的 bean,則 Spring 將繼續(xù)檢查下一個(gè)構(gòu)造函數(shù)。
如果沒有任何構(gòu)造函數(shù)可以匹配,則 Spring 將拋出一個(gè)異常。但是,可以使用 @Autowired(required=false) 注解來(lái)取消必需的依賴關(guān)系,這意味著如果找不到與構(gòu)造函數(shù)參數(shù)類型匹配的bean,則 Spring 將不會(huì)拋出異常。
以下是一個(gè)簡(jiǎn)單的例子,說(shuō)明如何在 Spring 中使用構(gòu)造函數(shù)推斷:
public class MyBean {
private final MyDependency myDependency;
public MyBean(MyDependency myDependency) {
this.myDependency = myDependency;
}
public void doSomething() {
myDependency.doSomething();
}
}
在這個(gè)例子中,MyBean依賴于MyDependency。Spring 將使用構(gòu)造函數(shù)推斷自動(dòng)注入 MyDependency,而不需要在XML或Java配置文件中顯式指定。
@Configuration
public class AppConfig {
@Bean
public MyDependency myDependency() {
return new MyDependency();
}
@Bean
public MyBean myBean() {
return new MyBean(myDependency());
}
}
在這個(gè)例子中,AppConfig 類使用 @Configuration 注解指定一個(gè) Spring 應(yīng)用程序上下文,并定義兩個(gè)bean:MyDependency 和 MyBean。在 MyBean 的構(gòu)造函數(shù)中,我們將 MyDependency 作為參數(shù)傳遞,Spring 將使用構(gòu)造函數(shù)推斷自動(dòng)注入 MyDependency。
構(gòu)造函數(shù)推斷的限制
構(gòu)造函數(shù)推斷有一些限制,例如:
如果有多個(gè)構(gòu)造函數(shù)可以匹配,則 Spring 將拋出一個(gè)異常。在這種情況下,您需要使用 @Qualifier 注解來(lái)指定要注入的 bean。
如果構(gòu)造函數(shù)參數(shù)是原始類型(例如int、float、boolean等),則 Spring 無(wú)法推斷它們。在這種情況下,您需要使用 @Value 注解將值直接注入到構(gòu)造函數(shù)參數(shù)中。
如果構(gòu)造函數(shù)參數(shù)是數(shù)組或集合,則 Spring 無(wú)法推斷它們。在這種情況下,您需要使用 @Qualifier 注解和 @Autowired 的 List 或 Set 類型的字段來(lái)手動(dòng)注入數(shù)組或集合。
源碼解析
Spring 使用 BeanWrapperImpl 類來(lái)執(zhí)行構(gòu)造函數(shù)推斷。BeanWrapperImpl 類是 Spring 的核心類之一,它提供了一種方便的方式來(lái)對(duì) Java 對(duì)象進(jìn)行包裝和訪問。以下是 Spring 中用于執(zhí)行構(gòu)造函數(shù)推斷的 BeanWrapperImpl 類的源代碼:
public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWrapper {
// ...
@Override
public Object createInstance() throws BeansException {
// 獲取Bean的構(gòu)造函數(shù)
Constructor<?> constructorToUse = this.constructorResolver.autowireConstructor;
if (constructorToUse == null) {
throw new BeansException("No default constructor found");
}
try {
// 使用構(gòu)造函數(shù)創(chuàng)建Bean實(shí)例,并返回
return constructorToUse.newInstance(getConstructorArgumentValues(constructorToUse), getBeanClassLoader());
}
catch (Throwable ex) {
throw new BeanCreationException("Could not instantiate bean", ex);
}
}
// ...
private Constructor<?> autowireConstructor;
// ...
public BeanWrapperImpl(Class<?> clazz) {
super();
this.objectType = clazz;
this.propertyEditorRegistry = new SimpleTypeConverter();
this.constructorResolver = new ConstructorResolver(this.objectType, this);
}
// ...
private class ConstructorResolver {
// ...
public ConstructorResolver(Class<?> clazz, BeanWrapperImpl bw) {
// 查找可以使用的構(gòu)造函數(shù)并將其緩存
Constructor<?>[] candidates = clazz.getDeclaredConstructors();
Constructor<?> autowireCandidate = null;
int numAutowireCandidates = 0;
for (Constructor<?> candidate : candidates) {
if (candidate.isAnnotationPresent(Autowired.class)) {
autowireCandidate = candidate;
numAutowireCandidates++;
}
}
if (numAutowireCandidates == 1) {
this.autowireConstructor = autowireCandidate;
}
else if (numAutowireCandidates > 1) {
throw new BeansException("Multiple autowire constructors found");
}
}
// ...
}
// ...
}
在BeanWrapperImpl 類中,構(gòu)造函數(shù)推斷是在 createInstance() 方法中執(zhí)行的。該方法首先獲取與Bean匹配的構(gòu)造函數(shù)(由constructorResolver.autowireConstructor決定),然后使用該構(gòu)造函數(shù)創(chuàng)建 Bean 實(shí)例。
在 ConstructorResolver 內(nèi)部類中,構(gòu)造函數(shù)推斷是通過查找?guī)в?@Autowired 注解的構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)的。如果找到了一個(gè)帶有 Autowired注解 的構(gòu)造函數(shù),則它將被緩存到 autowireConstructor 字段中,并在 createInstance() 方法中使用。
結(jié)論
構(gòu)造函數(shù)自動(dòng)注入是 Spring 的一個(gè)非常強(qiáng)大的功能,它可以大大簡(jiǎn)化 bean 的配置和管理。我們深入探討了 Spring 構(gòu)造函數(shù)推斷的底層原理,并解釋了 Spring 是如何實(shí)現(xiàn)它的,還提供了一個(gè)簡(jiǎn)單的例子和源代碼解析,以幫助大家更好地了解構(gòu)造函數(shù)推斷的工作方式。
以上就是一文詳解Spring構(gòu)造函數(shù)推斷的詳細(xì)內(nèi)容,更多關(guān)于Spring 構(gòu)造函數(shù)推斷的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Boot整合SSE實(shí)時(shí)通信的問題小結(jié)
本文介紹了服務(wù)器發(fā)送事件(Server-Sent Events,SSE)技術(shù),其主要特點(diǎn)包括單向數(shù)據(jù)流、自動(dòng)重連、自定義事件類型等,SSE適用于實(shí)時(shí)更新場(chǎng)景,如新聞推送、評(píng)論系統(tǒng)等,感興趣的朋友跟隨小編一起看看吧2025-01-01
SpringBoot 如何優(yōu)雅的實(shí)現(xiàn)跨服務(wù)器上傳文件的示例
這篇文章主要介紹了SpringBoot 如何優(yōu)雅的實(shí)現(xiàn)跨服務(wù)器上傳文件的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2006-11-11
SpringCloud持久層框架MyBatis Plus的使用與原理解析
MyBatisPlus為MyBatis的增強(qiáng)版,專注于簡(jiǎn)化數(shù)據(jù)庫(kù)操作,提供自動(dòng)化CRUD、內(nèi)置分頁(yè)和樂觀鎖等功能,極大提升開發(fā)效率,在SpringCloud微服務(wù)架構(gòu)中,MyBatisPlus通過插件機(jī)制和自動(dòng)生成代碼功能,有效支持企業(yè)級(jí)應(yīng)用和分布式系統(tǒng)的開發(fā)2024-10-10
Java中 URL實(shí)現(xiàn)斷點(diǎn)下載
Java中 URL實(shí)現(xiàn)斷點(diǎn)下載,需要的朋友可以參考一下2013-03-03
java字符串日期類Date和Calendar相互轉(zhuǎn)化及相關(guān)常用方法
Java語(yǔ)言的Calendar(日歷),Date(日期),和DateFormat(日期格式)組成了Java標(biāo)準(zhǔn)的一個(gè)基本但是非常重要的部分,下面這篇文章主要給大家介紹了關(guān)于java字符串日期類Date和Calendar相互轉(zhuǎn)化及相關(guān)常用方法的相關(guān)資料,需要的朋友可以參考下2023-12-12

