@Autowired
一、基本信息
?? 作者 - Lex ?? 博客 - 我的CSDN ?? 文章目錄 - 所有文章 ?? 源碼地址 - @Autowired源碼
二围小、注解描述
@Autowired
注解昵骤,用于實現(xiàn)依賴注入(Dependency Injection, DI)。當(dāng)我們在 Spring 中定義了一個 Bean 并想要使用另一個 Bean 時肯适,可以使用 @Autowired
注解來自動注入所需的 Bean变秦,而我們無需手動查找和配置它。
三框舔、接口源碼
@Autowired
注解是 Spring 框架自 2.5 版本開始引入的一個核心注解蹦玫,該注解用于告知 Spring 框架的依賴注入工具自動注入所需的依賴。
/**
* 通過Spring的依賴注入機制標(biāo)記構(gòu)造函數(shù)刘绣、字段樱溉、setter方法或配置方法。
* 這是JSR-330 Inject 注解的一種替代额港,增加了必需與可選的語義。
*
* 自動注入的構(gòu)造函數(shù):
* 任何給定的bean類只有一個構(gòu)造函數(shù)可以聲明此注解歧焦,且其required屬性設(shè)置為 true移斩,
* 表示當(dāng)作為Spring bean使用時要自動注入的構(gòu)造函數(shù)肚医。如果required屬性設(shè)置為true,
* 則只能有一個構(gòu)造函數(shù)被標(biāo)記為Autowired向瓷。如果多個非必需的構(gòu)造函數(shù)聲明了這個注解肠套,
* 它們都會被視為自動注入的候選者。Spring會選擇可以滿足最多依賴的構(gòu)造函數(shù)進行注入猖任。如果沒有一個候選者滿足條件你稚,
* 則會使用默認(rèn)的構(gòu)造函數(shù)。如果一個類聲明了多個構(gòu)造函數(shù)朱躺,但沒有一個使用Autowired刁赖,
* 則會使用默認(rèn)的構(gòu)造函數(shù)。如果一個類從一開始就只聲明了一個構(gòu)造函數(shù)长搀,它總是會被使用宇弛,即使沒有被標(biāo)記。被標(biāo)記的構(gòu)造函數(shù)不需要是public的源请。
*
* 自動注入的字段:
* 字段會在bean構(gòu)造完成后注入枪芒,任何配置方法調(diào)用之前。配置字段不需要是public的谁尸。
*
* 自動注入的方法:
* 配置方法可以有任意名稱和任意數(shù)量的參數(shù)舅踪;其中每一個參數(shù)都會通過Spring容器中的一個匹配的bean進行自動注入。
* Bean屬性的setter方法在實質(zhì)上只是這種通用配置方法的一個特例良蛮。這些配置方法不需要是public的抽碌。
*
* 自動注入的參數(shù):
* 盡管從Spring 5.0開始Autowired可以在方法或構(gòu)造函數(shù)的單獨參數(shù)上聲明,
* 但框架的大部分都會忽略這樣的聲明背镇。唯一支持自動注入?yún)?shù)的Spring核心部分是
* spring-test模塊中的JUnit Jupiter支持咬展。
*
* 多參數(shù)與'required'語義:
* 對于多參數(shù)的構(gòu)造函數(shù)或方法,required屬性適用于所有參數(shù)瞒斩。
*
* 自動裝配數(shù)組破婆、集合和映射:
* 對于數(shù)組、Collection或Map類型的依賴胸囱,容器會自動注入所有匹配聲明的值類型的bean祷舀。
* 對于這種目的,map的鍵必須聲明為類型String烹笔,它會解析為相應(yīng)的bean名稱裳扯。
*
* 在BeanPostProcessor或BeanFactoryPostProcessor中不支持:
* 請注意,實際的注入是通過BeanPostProcessor執(zhí)行的谤职,這意味著我們不能使用Autowired在
* BeanPostProcessor或BeanFactoryPostProcessor類型中進行注入饰豺。
*
* @author Juergen Hoeller
* @author Mark Fisher
* @author Sam Brannen
* @since 2.5
* @see AutowiredAnnotationBeanPostProcessor
* @see Qualifier
* @see Value
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* 聲明注解的依賴是否是必需的。
* 默認(rèn)值為true允蜈。
*/
boolean required() default true;
}
四冤吨、主要功能
-
自動注入依賴
- 不需要明確指定 bean 之間的關(guān)系蒿柳,Spring 會自動找到并注入所需的依賴。
-
字段注入
- 可以直接標(biāo)記在類的字段上漩蟆,使得該字段在 Bean 初始化時被自動注入垒探。
-
構(gòu)造函數(shù)注入
- 當(dāng)標(biāo)記在構(gòu)造函數(shù)上時,該構(gòu)造函數(shù)會被用于創(chuàng)建 bean 實例并注入所需的依賴怠李。
-
方法注入
- 當(dāng)標(biāo)記在 setter 方法或其他方法上時圾叼,這些方法會在 Bean 初始化時被調(diào)用以注入依賴。
-
指定必需性
- 通過
required
屬性捺癞,可以指定某個依賴是否是必需的夷蚊。如果標(biāo)記為必需但沒有找到相應(yīng)的依賴,Spring 會拋出異常翘簇。
- 通過
五撬码、最佳實踐
首先來看看啟動類入口,上下文環(huán)境使用AnnotationConfigApplicationContext
(此類是使用Java注解來配置Spring容器的方式)版保,構(gòu)造參數(shù)我們給定了一個MyConfiguration
組件類呜笑。然后從Spring上下文中獲取一個MyController
類型的bean并調(diào)用了showService
方法,
public class AutowiredApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
MyController controller = context.getBean(MyController.class);
controller.showService();
}
}
在MyConfiguration
類中彻犁,使用了@ComponentScan("com.xcs.spring")
注解告訴 Spring 在指定的包(在這里是 "com.xcs.spring
")及其子包中搜索帶有 @Component
叫胁、@Service
、@Repository
和 @Controller
等注解的類汞幢,并將它們自動注冊為 beans驼鹅。這樣,spring就不必為每個組件明確寫一個 bean 定義森篷。Spring 會自動識別并注冊它們输钩。
@Configuration
@ComponentScan("com.xcs.spring")
public class MyConfiguration {
}
Spring 容器在初始化 MyController
時自動注入一個 MyService
類型的 bean 到 myService
字段。
@Controller
public class MyController {
@Autowired
private MyService myService;
public void showService(){
System.out.println("myService = " + myService);
}
}
MyService
是一個簡單的服務(wù)類仲智,但我們沒有定義任何方法或功能买乃。
@Service
public class MyService {
}
運行結(jié)果發(fā)現(xiàn),我們使用 @Autowired
注解的功能钓辆,在我們的 Spring 上下文中工作正常剪验,并且它成功地自動注入了所需的依賴關(guān)系。
myService = com.xcs.spring.service.MyService@4a883b15
六前联、時序圖
sequenceDiagram
Title: @Autowired注解時序圖
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:applyMergedBeanDefinitionPostProcessors(mbd,beanType,beanName)<br>應(yīng)用Bean定義的后置處理器
AbstractAutowireCapableBeanFactory->>AutowiredAnnotationBeanPostProcessor:postProcessMergedBeanDefinition(beanDefinition,beanType,beanName)<br>處理已合并的Bean定義
AutowiredAnnotationBeanPostProcessor->>AutowiredAnnotationBeanPostProcessor:findAutowiringMetadata(beanName,clazz,pvs)<br>查找自動注入的元數(shù)據(jù)
AutowiredAnnotationBeanPostProcessor->>AutowiredAnnotationBeanPostProcessor:buildAutowiringMetadata(clazz)<br>構(gòu)建自動注入的元數(shù)據(jù)
AutowiredAnnotationBeanPostProcessor->>ReflectionUtils:doWithLocalFields(clazz,fc)<br>處理類的本地字段
ReflectionUtils->>AutowiredAnnotationBeanPostProcessor:解析有@Autowired注解的字段
AutowiredAnnotationBeanPostProcessor->>ReflectionUtils:doWithLocalMethods(clazz,fc)<br>處理類的本地方法
ReflectionUtils->>AutowiredAnnotationBeanPostProcessor:解析有@Autowired注解的方法
AutowiredAnnotationBeanPostProcessor->>AutowiredAnnotationBeanPostProcessor:injectionMetadataCache.put(cacheKey, metadata)<br>將元數(shù)據(jù)存入緩存
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:populateBean(beanName,mbd,bw)<br>填充Bean的屬性值
AbstractAutowireCapableBeanFactory->>AutowiredAnnotationBeanPostProcessor:postProcessProperties(pvs,bean,beanName)<br>后處理Bean的屬性
AutowiredAnnotationBeanPostProcessor->>AutowiredAnnotationBeanPostProcessor:findAutowiringMetadata(beanName,clazz,pvs)<br>再次查找自動注入的元數(shù)據(jù)
Note right of AutowiredAnnotationBeanPostProcessor:<br>從緩存中獲取注入的元數(shù)據(jù)
AutowiredAnnotationBeanPostProcessor->>InjectionMetadata:inject(bean, beanName, pvs)<br>執(zhí)行實際的屬性注入
InjectionMetadata->>AutowiredFieldElement:inject(target, beanName, pvs)<br>注入特定的字段元素
AutowiredFieldElement->>AutowiredFieldElement:resolveFieldValue(field,bean,beanName)<br>解析字段的值
AutowiredFieldElement->>DefaultListableBeanFactory:resolveDependency(desc, beanName, autowiredBeanNames, typeConverter)<br>解析字段的依賴
DefaultListableBeanFactory->>DefaultListableBeanFactory:doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter)<br>解析指定的依賴關(guān)系
DefaultListableBeanFactory->>DefaultListableBeanFactory:findAutowireCandidates(beanName, type, descriptor)<br>查找符合自動裝配條件的候選 Bean
DefaultListableBeanFactory->>DefaultListableBeanFactory:addCandidateEntry(result, candidate, descriptor, requiredType)<br>向結(jié)果集中添加候選 Bean
DefaultListableBeanFactory->>AbstractBeanFactory:getType(name)<br>獲取指定 Bean 的類型
AbstractBeanFactory->>DefaultListableBeanFactory:返回被依賴Bean的類<br>返回依賴 Bean 的實際類
DefaultListableBeanFactory->>DependencyDescriptor:resolveCandidate(beanName, requiredType, beanFactory)<br>解析候選的依賴 Bean
DependencyDescriptor->>AbstractBeanFactory:getBean(name)<br>獲取指定的 Bean 實例
AbstractBeanFactory->>DependencyDescriptor:<br>返回具體的依賴 Bean 實例
DependencyDescriptor->>DefaultListableBeanFactory:<br>返回依賴的 Bean 實例給工廠
DefaultListableBeanFactory->>AutowiredFieldElement:<br>返回依賴的 Bean 給字段注入器
AutowiredFieldElement->>Field:field.set(bean, value)<br>實際設(shè)置 Bean 的字段值
七功戚、源碼分析
前置條件
在Spring中,AutowiredAnnotationBeanPostProcessor
是處理@Autowired
等注解的關(guān)鍵類似嗤,它實現(xiàn)了下述兩個接口啸臀。因此,為了深入理解@Autowired
的工作方式烁落,研究這個類是非常有用的乘粒。簡而言之席揽,為了完全理解@Autowired
的工作機制,了解下述接口確實是必要的谓厘。這兩個接口提供了對bean生命周期中關(guān)鍵階段的干預(yù),從而允許進行屬性注入和其他相關(guān)的操作寸谜。
-
MergedBeanDefinitionPostProcessor
接口- 此接口提供的
postProcessMergedBeanDefinition
方法允許后處理器修改合并后的bean定義竟稳。合并后的bean定義是一個已經(jīng)考慮了所有父bean定義屬性的bean定義。對于@Autowired
注解的處理熊痴,這一步通常涉及到收集需要被解析的@Autowired
注解信息并準(zhǔn)備對其進行后續(xù)處理他爸。 - ?? MergedBeanDefinitionPostProcessor接口傳送門
- 此接口提供的
-
InstantiationAwareBeanPostProcessor
接口- 此接口提供了幾個回調(diào)方法,允許后處理器在bean實例化之前和實例化之后介入bean的創(chuàng)建過程果善。特別是诊笤,
postProcessProperties
方法允許后處理器對bean的屬性進行操作。對于@Autowired
注解巾陕,這通常需要在屬性設(shè)置或依賴注入階段對 bean 進行處理讨跟,并將解析得到的值注入到bean中。 - ?? InstantiationAwareBeanPostProcessor接口傳送門
- 此接口提供了幾個回調(diào)方法,允許后處理器在bean實例化之前和實例化之后介入bean的創(chuàng)建過程果善。特別是诊笤,
收集階段
在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
方法中鄙煤,主要確保給定的bean定義與其預(yù)期的自動裝配元數(shù)據(jù)一致晾匠。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 對于給定的bean名稱和類型,它首先嘗試查找相關(guān)的InjectionMetadata梯刚,這可能包含了該bean的字段和方法的注入信息
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
// 使用找到的InjectionMetadata來驗證bean定義中的配置成員是否與預(yù)期的注入元數(shù)據(jù)匹配凉馆。
metadata.checkConfigMembers(beanDefinition);
}
在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
方法中,確保了始終為給定的bean名稱和類獲取最新和相關(guān)的InjectionMetadata
亡资,并利用緩存機制優(yōu)化性能澜共。
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// 如果beanName為空,則使用類名作為緩存鍵锥腻。
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 首先嘗試從并發(fā)緩存中獲取InjectionMetadata嗦董。
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 檢查獲取到的元數(shù)據(jù)是否需要刷新。
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 使用雙重檢查鎖定確保線程安全旷太。
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 如果有舊的元數(shù)據(jù)展懈,清除它。
if (metadata != null) {
metadata.clear(pvs);
}
// 為給定的類構(gòu)建新的InjectionMetadata供璧。
metadata = buildAutowiringMetadata(clazz);
// 將新構(gòu)建的元數(shù)據(jù)更新到緩存中存崖。
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
// 返回找到的或新構(gòu)建的元數(shù)據(jù)。
return metadata;
}
在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
方法中睡毒,查找類及其所有父類中的字段和方法来惧,以找出所有帶有自動裝配注解的字段和方法,并為它們創(chuàng)建一個統(tǒng)一的InjectionMetadata
對象演顾。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// 檢查類是否含有自動裝配注解供搀,若無則直接返回空的InjectionMetadata隅居。
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
// 初始化存放注入元素的列表。
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
// 當(dāng)前類中要注入的元素列表葛虐。
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 處理類中的所有字段胎源。
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 查找字段上的自動裝配注解。
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// ... [代碼部分省略以簡化]
boolean required = determineRequiredStatus(ann);
// 創(chuàng)建一個新的AutowiredFieldElement并加入到列表屿脐。
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 處理類中的所有方法涕蚤。
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 查找方法上的自動裝配注解。
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
// ... [代碼部分省略以簡化]
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 創(chuàng)建一個新的AutowiredMethodElement并加入到列表的诵。
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
// 將當(dāng)前類的注入元素加入到總的注入元素列表的開頭万栅。
elements.addAll(0, currElements);
// 處理父類。
targetClass = targetClass.getSuperclass();
}
// 循環(huán)直至Object類西疤。
while (targetClass != null && targetClass != Object.class);
// 返回為元素列表創(chuàng)建的新的InjectionMetadata烦粒。
return InjectionMetadata.forElements(elements, clazz);
}
在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#autowiredAnnotationTypes
字段中,主要的用途是告訴AutowiredAnnotationBeanPostProcessor
哪些注解它應(yīng)該處理代赁。當(dāng)Spring容器解析bean定義并創(chuàng)建bean實例時扰她,如果這個bean的字段、方法或構(gòu)造函數(shù)上的注解被包含在這個autowiredAnnotationTypes
集合中芭碍,那么AutowiredAnnotationBeanPostProcessor
就會對它進行處理义黎。
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
// ... [代碼部分省略以簡化]
}
注入階段
在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties
方法中,用于處理bean屬性的后處理豁跑,特別是通過@Autowired
等注解進行的屬性注入廉涕。
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 獲取與bean名稱和類相關(guān)的InjectionMetadata。
// 這包括該bean需要進行注入的所有字段和方法艇拍。
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 使用獲取到的InjectionMetadata狐蜕,實際進行屬性的注入。
metadata.inject(bean, beanName, pvs);
}
// 如果在注入過程中出現(xiàn)BeanCreationException卸夕,直接拋出层释。
catch (BeanCreationException ex) {
throw ex;
}
// 捕獲其他異常,并以BeanCreationException的形式拋出快集,提供詳細的錯誤信息贡羔。
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
// 返回原始的PropertyValues,因為這個方法主要關(guān)注依賴注入而不是修改屬性个初。
return pvs;
}
在org.springframework.beans.factory.annotation.InjectionMetadata#inject
方法中乖寒,主要目的是將所有需要注入的元素(例如帶有@Autowired
等注解的字段或方法)注入到目標(biāo)bean中。
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 獲取已經(jīng)檢查的元素院溺。通常楣嘁,在初始化階段,所有的元素都會被檢查一次垂睬。
Collection<InjectedElement> checkedElements = this.checkedElements;
// 如果已經(jīng)有檢查過的元素上煤,則使用它們恩急,否則使用所有注入的元素恍涂。
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
// 如果有需要注入的元素...
if (!elementsToIterate.isEmpty()) {
// 遍歷每個元素并注入到目標(biāo)bean中。
for (InjectedElement element : elementsToIterate) {
// 對每個元素(字段或方法)執(zhí)行注入操作昆咽。
element.inject(target, beanName, pvs);
}
}
}
在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
方法中金踪,首先檢查字段的值是否已經(jīng)被緩存捺氢。如果已緩存买雾,則從緩存中獲取馒胆,否則重新解析。然后凝果,它確保字段是可訪問的(特別是對于私有字段),并將解析的值設(shè)置到目標(biāo)bean的相應(yīng)字段中睦尽。
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 步驟1. 獲取代表帶有@Autowired注解的字段的Field對象器净。
Field field = (Field) this.member;
Object value;
// 步驟2. 如果字段的值已經(jīng)被緩存(即先前已解析過),則嘗試從緩存中獲取当凡。
if (this.cached) {
try {
// 從緩存中獲取已解析的字段值山害。
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// 如果緩存中的bean已被意外刪除 -> 重新解析。
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 步驟3. 如果字段值未被緩存沿量,直接解析浪慌。
value = resolveFieldValue(field, bean, beanName);
}
// 步驟4. 如果解析到的值不為null...
if (value != null) {
// 步驟4.1. 使字段可訪問,這是必要的朴则,特別是當(dāng)字段是private時权纤。
ReflectionUtils.makeAccessible(field);
// 步驟4.2. 實際將解析的值注入到目標(biāo)bean的字段中。
field.set(bean, value);
}
}
首先來到org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
方法中的步驟3乌妒。在org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue
方法中汹想,通過beanFactory.resolveDependency
方法從Spring的bean工廠中解析字段的值。
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
// ... [代碼部分省略以簡化]
Object value;
try {
// 通過`beanFactory.resolveDependency`方法從Spring的bean工廠中解析字段的值
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
// ... [代碼部分省略以簡化]
return value;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
方法中撤蚊,首先嘗試獲取一個延遲解析代理古掏。如果無法獲得,它會進一步嘗試解析依賴侦啸。doResolveDependency
是實際進行解析工作的方法槽唾。
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ... [代碼部分省略以簡化]
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法中,嘗試解析一個特定的依賴光涂,首先查找所有可能的匹配的 bean庞萍,然后選擇一個最佳匹配的 bean。如果存在多個匹配的 bean 或沒有找到匹配的 bean忘闻,它會進行相應(yīng)的處理挂绰。
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ... [代碼部分省略以簡化]
try {
// 如果存在快捷解決依賴的方法,使用它
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 獲取依賴的類型
Class<?> type = descriptor.getDependencyType();
// ... [代碼部分省略以簡化]
// 步驟1. 根據(jù)依賴描述符查找匹配的bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 如果沒有找到匹配的bean
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 如果依賴是必需的,拋出異常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 當(dāng)找到多個匹配的bean
if (matchingBeans.size() > 1) {
// 確定最佳的自動裝配候選者
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 如果不能確定唯一的bean葵蒂,嘗試解析不唯一的依賴
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 只找到一個匹配的bean
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// 添加自動裝配的bean名到集合
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 步驟2. 如果候選者是一個類交播,實例化它
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
// ... [代碼部分省略以簡化]
return result;
}
// ... [代碼部分省略以簡化]
}
我們來到在org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法中的步驟1。在org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
方法中践付,首先基于給定的類型獲取所有可能的bean名秦士。接著,對于每一個可能的候選bean永高,它檢查該bean是否是一個合適的自動注入候選隧土,如果是,它將這個bean添加到結(jié)果集中命爬。最后,方法返回找到的所有合適的候選bean饲宛。
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 根據(jù)所需的類型皆愉,包括所有父工廠中的bean,獲取所有可能的bean名
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
// ... [代碼部分省略以簡化]
// 遍歷所有候選bean名
for (String candidate : candidateNames) {
// 如果候選bean不是正在查找的bean本身并且它是一個合適的自動注入候選
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 添加這個候選bean到結(jié)果中
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// ... [代碼部分省略以簡化]
// 返回找到的所有候選bean
return result;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#addCandidateEntry
方法中艇抠,主要獲取候選bean的類型幕庐,并將其添加到候選bean的集合中。
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
DependencyDescriptor descriptor, Class<?> requiredType) {
// ... [代碼部分省略以簡化]
candidates.put(candidateName, getType(candidateName));
}
在org.springframework.beans.factory.support.AbstractBeanFactory#getType(name)
方法中家淤,通過bean的名字來獲取對應(yīng)bean的類型异剥。
public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getType(name, true);
}
我們來到在org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法中的步驟2。在org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate
方法中絮重,最后發(fā)現(xiàn)@Autowired
的整個流程最終還是從Spring容器中獲取一個bean實例并注入到相應(yīng)的字段或構(gòu)造函數(shù)參數(shù)中冤寿。
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
最后我們來到org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
方法中的步驟4.2。在 AutowiredFieldElement#inject
方法內(nèi)部青伤,通過resolveFieldValue(field, bean, beanName)
方法疚沐,來確定了正確的bean值并滿足某個字段的 @Autowired
注解,將使用反射來實際設(shè)置這個值潮模。具體地說亮蛔,它會使用 Field
類的 set
方法來為目標(biāo)對象的這個字段設(shè)置相應(yīng)的值。這就是 @Autowired
在字段上使用時如何使得Spring能夠自動為這個字段注入值的背后原理擎厢。
// 步驟4. 如果解析到的值不為null...
if (value != null) {
// 步驟4.1. 使字段可訪問究流,這是必要的,特別是當(dāng)字段是private時动遭。
ReflectionUtils.makeAccessible(field);
// 步驟4.2. 實際將解析的值注入到目標(biāo)bean的字段中芬探。
field.set(bean, value);
}
八、注意事項
-
默認(rèn)情況下厘惦,依賴是必需的
- 如果Spring找不到匹配的bean來注入偷仿,它會拋出一個異常哩簿。我們可以通過將
required
屬性設(shè)置為false
來使其變?yōu)榉潜匦瑁?code>@Autowired(required=false)。
- 如果Spring找不到匹配的bean來注入偷仿,它會拋出一個異常哩簿。我們可以通過將
-
類型匹配
- 默認(rèn)情況下酝静,Spring使用類型匹配來解析依賴节榜。如果有多個匹配的bean,它會拋出一個異常别智。
-
使用
@Qualifier
- 如果有多個相同類型的bean宗苍,我們可以使用
@Qualifier
注解來指定bean的名稱,以解決歧義薄榛。
- 如果有多個相同類型的bean宗苍,我們可以使用
-
循環(huán)依賴
-
@Autowired
可能導(dǎo)致循環(huán)依賴的問題讳窟。例如,A依賴于B敞恋,而B依賴于A丽啡。Spring有一定的機制來處理單例作用域的bean的循環(huán)依賴,但對于原型作用域的bean硬猫,循環(huán)依賴會導(dǎo)致異常补箍。
-
-
注入位置
- 我們可以在字段、構(gòu)造函數(shù)浦徊、或setter方法上使用
@Autowired
。但是天梧,推薦的做法是在構(gòu)造函數(shù)上使用它盔性,這樣可以確保所有的依賴在對象創(chuàng)建時都已經(jīng)注入。
- 我們可以在字段、構(gòu)造函數(shù)浦徊、或setter方法上使用
-
影響范圍
- 使用
@Autowired
時呢岗,請注意不要在大范圍的bean(例如單例)中注入小范圍的bean(例如原型)冕香,除非我們清楚地知道自己在做什么。
- 使用
-
考慮使用構(gòu)造函數(shù)注入
- 使用構(gòu)造函數(shù)注入可以確保bean在構(gòu)造時已完全初始化后豫,從而使bean處于不變的狀態(tài)悉尾。這也有助于在單元測試中模擬依賴關(guān)系。
-
私有字段注入
- 盡管可以將
@Autowired
應(yīng)用于私有字段挫酿,但這意味著Spring通過反射繞過了正常的Java訪問控制來注入字段构眯,這可能不是最佳實踐。
- 盡管可以將
-
不支持靜態(tài)字段
-
@Autowired
不能用于靜態(tài)字段早龟。這是因為靜態(tài)字段屬于類而不是實例惫霸,而Spring是通過實例進行依賴注入的。
-
-
不支持靜態(tài)方法
-
@Autowired
也不能用于靜態(tài)setter方法或其他靜態(tài)方法
-
九葱弟、總結(jié)
最佳實踐總結(jié)
-
上下文初始化
- 當(dāng)我們創(chuàng)建
AnnotationConfigApplicationContext
并提供MyConfiguration
類作為參數(shù)時壹店,Spring 開始初始化上下文。這意味著它會加載所有的bean定義并準(zhǔn)備創(chuàng)建實例芝加。
- 當(dāng)我們創(chuàng)建
-
組件掃描
- 在
MyConfiguration
類中硅卢,我們使用了@ComponentScan
注解指定了掃描的包路徑。這使得Spring掃描指定包和其子包中的所有類,并查找標(biāo)記為@Component
将塑、@Service
脉顿、@Repository
和@Controller
等注解的類。找到后抬旺,Spring 會自動將這些類注冊為bean弊予。
- 在
-
依賴解析
- 在
MyController
類中,我們在myService
字段上使用了@Autowired
注解开财。這告訴Spring汉柒,當(dāng)創(chuàng)建MyController
bean時,需要找到一個MyService
類型的bean责鳍,并自動注入到該字段中碾褂。
- 在
-
實例化并注入
- 當(dāng)我們從上下文中請求
MyController
類型的bean時,Spring會先創(chuàng)建MyController
的一個實例历葛。但在此之前正塌,它會查看所有帶有@Autowired
注解的字段,然后為這些字段找到匹配的bean并注入恤溶。 - 在我們的例子中乓诽,Spring找到了
MyService
類型的bean并將其注入到了myService
字段中。
- 當(dāng)我們從上下文中請求
-
執(zhí)行業(yè)務(wù)邏輯
- 在
showService
方法被調(diào)用時咒程,它簡單地打印了myService
字段鸠天。由于這個字段已經(jīng)被成功地自動注入,所以我們看到了預(yù)期的輸出帐姻,證明@Autowired
功能正常稠集。
- 在
-
結(jié)果
- 最終輸出顯示了
myService
已經(jīng)被成功地注入到MyController
中,并顯示了其實例的內(nèi)存地址饥瓷。
- 最終輸出顯示了
源碼分析總結(jié)
-
核心后處理器
-
AutowiredAnnotationBeanPostProcessor
是處理@Autowired
等注解的主要后處理器剥纷。它實現(xiàn)了兩個關(guān)鍵的接口,MergedBeanDefinitionPostProcessor
和InstantiationAwareBeanPostProcessor
呢铆,這兩個接口允許在bean的生命周期中的關(guān)鍵階段進行干預(yù)晦鞋,為屬性注入提供了機制。
-
-
收集階段
-
檢索Autowired的元數(shù)據(jù)
Spring首先使用
postProcessMergedBeanDefinition
方法確保給定的bean定義與其預(yù)期的自動裝配元數(shù)據(jù)一致棺克。在該方法中, Spring會嘗試查找與給定bean名稱和類型相關(guān)的
InjectionMetadata
鳖宾。這可能包括了該bean的字段和方法的注入信息。
-
尋找匹配的Autowiring元數(shù)據(jù)
- 在
findAutowiringMetadata
中逆航,Spring確保始終為給定的bean名稱和類獲取最新和相關(guān)的InjectionMetadata
鼎文。Spring也利用了緩存機制,以提高性能因俐。
- 在
-
構(gòu)建Autowiring元數(shù)據(jù)
在
buildAutowiringMetadata
方法中拇惋,Spring會查找類及其所有父類中的字段和方法周偎,以找出所有帶有自動裝配注解的字段和方法。然后撑帖,為這些字段和方法創(chuàng)建一個統(tǒng)一的
InjectionMetadata
對象蓉坎。
-
檢查注解類型
- 在
AutowiredAnnotationBeanPostProcessor
的構(gòu)造方法中,主要的目的是告訴這個后處理器它應(yīng)該處理哪些注解胡嘿。例如,@Autowired
就是這些注解之一蛉艾。
- 在
-
-
注入階段
-
處理bean屬性的后處理
在
postProcessProperties
中,Spring用于處理bean屬性的后處理衷敌,特別是通過@Autowired
進行的屬性注入勿侯。這涉及到實際將解析得到的值注入到bean中。
-
注入元數(shù)據(jù)的實際注入操作
在
InjectionMetadata#inject
方法中缴罗,這里會對bean進行屬性的實際注入助琐。Spring會遍歷每一個需要注入的元素,并執(zhí)行實際的注入操作面氓。
-
字段的實際注入
在
AutowiredFieldElement#inject
中兵钮,Spring首先會檢查字段的值是否已經(jīng)被緩存。如果已緩存舌界,則從緩存中獲取掘譬,否則重新解析。然后呻拌,它確保字段是可訪問的葱轩,并將解析的值設(shè)置到目標(biāo)bean的相應(yīng)字段中。
-
解析依賴
在
doResolveDependency
方法中柏锄,Spring開始嘗試解析一個特定的依賴酿箭。首先复亏,基于給定的類型趾娃,Spring會查找所有匹配的bean。
如果找到多個匹配的bean缔御,它會嘗試確定哪一個是最佳的自動裝配候選抬闷。
-
獲取bean的類型
在
addCandidateEntry
方法中,Spring主要獲取候選bean的類型耕突,并將其添加到候選bean的集合中笤成。使用
getType
方法,Spring可以通過bean的名字來獲取對應(yīng)bean的類型眷茁。
-
從Spring容器中獲取bean實例
- 在
resolveCandidate
中炕泳,即從Spring容器中獲取一個bean實例并注入到相應(yīng)的字段或構(gòu)造函數(shù)參數(shù)中。
- 在
-
反射注入
- 通過
field.set(bean, value)
來完成實際字段注入的步驟上祈,將解析出的bean實例(value)注入到目標(biāo)bean的對應(yīng)字段上培遵。這是整個@Autowired
流程的最終步驟
- 通過
-