Spring注解之@Autowired


前言

    說起Spring的@Autowired注解,想必大家已經熟悉的不能再熟悉了。本文就針對此最常用的注解,梳理一下它的功能和原理,爭取從源碼的角度將此注解講通,如有寫的不准確的地方,歡迎各位園友拍磚。

注:此篇博文基於Spring5.1.10.RELEASE,SpringBoot2.1.9.RELEASE

正文

    首先看一下@Autowired注解的源碼

 1 package org.springframework.beans.factory.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
10 @Retention(RetentionPolicy.RUNTIME)
11 @Documented
12 public @interface Autowired {
13 
14     /**
15      * Declares whether the annotated dependency is required.
16      * <p>Defaults to {@code true}.
17      */
18     boolean required() default true;
19 
20 }

    可以看到,此注解運行時生效,且適用范圍很廣,從構造器,到方法,到參數、屬性、注解,都可以加上@Autowired注解。它還有一個屬性required,此屬性用於控制如果找不到要依賴注入的對象時是否報錯,默認true即默認找不到要注入的對象時會報錯。下面我們慢慢梳理,將@Autowired的使用場景一一羅列出來。

一、普通用法,依賴注入成員變量

下面將要用的測試類貼出來,首先是接口

1 package com.mybokeyuan.springAutowiredDemo;
2 
3 public interface IndexInterface {
4 }

再就是兩個子類

1 package com.mybokeyuan.springAutowiredDemo;
2 
3 import org.springframework.stereotype.Component;
4 
5 @Component
6 public class IndexService implements IndexInterface{
7 
8 }
1 package com.mybokeyuan.springAutowiredDemo;
2 
3 import org.springframework.stereotype.Component;
4 
5 @Component
6 public class OtherIndexService implements IndexInterface{
7     
8 }

核心類(后續的各種場景演示均只基於此類進行改動)

 1 package com.mybokeyuan.springAutowiredDemo;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Component;
 5 
 6 @Component
 7 public class MyService {
 8 
 9     @Autowired
10     private IndexService indexService;
11 
12 }

掃描配置類

1 package com.mybokeyuan.springAutowiredDemo;
2 
3 import org.springframework.context.annotation.ComponentScan;
4 import org.springframework.context.annotation.Configuration;
5 
6 @Configuration
7 @ComponentScan("com.mybokeyuan.springAutowiredDemo")
8 public class AutowiredConfig {
9 }

main方法類

 1 package com.mybokeyuan.springAutowiredDemo.client;
 2 
 3 import com.mybokeyuan.springAutowiredDemo.AutowiredConfig;
 4 import com.mybokeyuan.springAutowiredDemo.MyService;
 5 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 6 
 7 public class DemoClientTest {
 8     public static void main(String[] args) {
 9         AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutowiredConfig.class);
10         System.out.println(ac.getBean(MyService.class));
11 
12     }
13 }

運行main方法時,如果在第10行打了斷點,會看到MyService中的indexService屬性已經依賴注入了值,這是我們最常使用@Autowired注解的場景。

二、依賴注入方法

 MyService類如下所示

 1 package com.mybokeyuan.springAutowiredDemo;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.stereotype.Component;
 6 
 7 import java.util.List;
 8 
 9 @Component
10 public class MyService {
11 
12     private IndexService indexService;
13 
14     @Autowired
15     public void getIndexInterf (IndexService index) {
16         indexService = index;
17     }
18 
19     @Autowired
20     private ApplicationContext applicationContext;
21 
22 }

運行main方法后,會發現該類中的indexService完成了注入,這樣的用法類似於set方法的功能。並且可以看到,applicationContext也注入了。所以往后就不要用ApplicationContextAware了,直接@Autowired輕快便捷的達到目的。

三、構造方法注入參數

 MyService類如下所示:

 1 package com.mybokeyuan.springAutowiredDemo;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Component;
 5 
 6 import java.util.List;
 7 
 8 @Component
 9 public class MyService {
10 
11 
12     private IndexService indexService;
13 
14     private List<IndexInterface> indexList;
15 
16     @Autowired
17     public MyService (List<IndexInterface> indexList, IndexService indexService) {
18         this.indexList = indexList;
19         this.indexService = indexService;
20     }
21 }

        運行后會發現成員變量indexList和indexService中已經注入了值。此處需要注意一點,如果有兩個自定義構造方法,兩個都沒加@Autowired注解,則會報錯,因為Spring不知道你要用哪個構造方法初始化;

如果只有一個構造方法加了@Autowired注解,那么就會用這個構造方法初始化;同理,如果有多個構造方法都加了@Autowired注解,那么還是會報錯。

四、注入Map、List等集合

 在【一、普通用法】中的MyService里添加幾個成員變量,如下所示:

 1 package com.mybokeyuan.springAutowiredDemo;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Component;
 5 
 6 import java.util.List;
 7 import java.util.Map;
 8 import java.util.Set;
 9 
10 @Component
11 public class MyService {
12     
13     @Autowired
14     private IndexService indexService;
15 
16     @Autowired
17     private List<IndexInterface> indexList;
18 
19     @Autowired
20     private Map<String, IndexInterface> indexMap;
21 
22     @Autowired
23     private Set<IndexInterface> indexSet;
24 }

再次運行main方法,在斷點中可以看到從Spring中獲取到的MyService對象中,已經完成了對后面三個集合的依賴注入,如下圖所示:

 

可以看到,IndexInterface接口的兩個實現類全部注入到了集合中,且Map里面的key默認就是兩個實現類各自的beanName。

 

五、源碼分析

        看了上面的各種使用場景,想必大家會對這個最熟悉的注解有了一絲陌生的感覺,不過不要緊,下面咱們慢慢來脫下TA的神秘衣服,對ta重新熟悉起來。我這里是以下面的MyService類為例子進行的源碼debug分析。

 1 package com.mybokeyuan.springAutowiredDemo;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.stereotype.Component;
 6 
 7 import java.util.List;
 8 
 9 @Component
10 public class MyService {
11 
12 
13     private IndexService indexService;
14 
15     private List<IndexInterface> indexList;
16 
17     @Autowired
18     public void getIndexInterf (IndexService index) {
19         indexService = index;
20     }
21 
22     @Autowired
23     private ApplicationContext applicationContext;
24 
25     @Autowired
26     public MyService (List<IndexInterface> indexList) {
27         this.indexList = indexList;
28     }
29 }

        首先在AutowiredAnnotationBeanPostProcessor#postProcessProperties的方法中打上一個斷點,然后右鍵斷點加上條件過濾 beanName.equals("myService"),debug運行main方法,會在斷點處停住,此時我們的調用棧是下圖這樣的:

        相信對Spring源碼有過了解的園友對調用棧中的方法都不陌生,從下往上看,先經過了refresh方法,在finishBeanFactoryInitialization方法中getBean,然后走getObject的時候觸發bean的初始化。

bean的初始化是一個很復雜地方,在AbstractAutowireCapableBeanFactory#doCreateBean方法中,先創建一個BeanWrapper,它的內部成員變量wrappedObject中存放的就是實例化的MyService對象,只是此時未完成初始化,所以屬性都是null(如下圖所示)。再往后進入populateBean方法進行屬性注入,這才逐漸逼近我們的目的地。

         不過在進入populateBean之前,需要先去看一下前置方法,即BeanWrapper創建的方法createBeanInstance。Spring在這個方法中先推斷出合適的構造方法,然后實例化bean。在推斷構造方法的時候(AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors方法中調用了AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors方法進行的推斷),有一個篩選標准就是會根據是否有@Autowired注解來選擇用哪個構造器,具體詳見AutowiredAnnotationBeanPostProcessor#findAutowiredAnnotation方法,此方法如下所示,功能就是看看當前構造器上加沒加注解。

 1     @Nullable
 2     private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
 3         if (ao.getAnnotations().length > 0) {  // autowiring annotations have to be local
 4             for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {// 此集合中只有兩個值,一個是Autowired注解,一個是Value注解
 5                 AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
 6                 if (attributes != null) {
 7                     return attributes;
 8                 }
 9             }
10         }
11         return null;
12     }

此處構造器的推斷和屬性注入,就是使用場景三【三、構造方法注入參數】中,@Autowired注解加在構造器上發揮的作用。

走完createBeanInstance方法得到的BeanWrapper中,可以看到屬性wrappedObject中已經對indexList進行了依賴注入

 

進行到這里,有必要重新梳理清楚類構造器注入時的調用關系,示例的調用棧圖如下所示:

1、在myService對象進行實例化調用構造器時,執行AbstractAutowireCapableBeanFactory#autowireConstructor方法;

2、進入到另一個類ConstructorResolver的autowireConstructor方法中;

2.1、調用同類下的resolveAutowiredArgument方法,該方法會調用DefaultListableBeanFactory下的resolveDependency方法,此方法會調用到findAutowireCandidates方法,在該方法中有如下代碼

1 for (String candidate : candidateNames) {
2             if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) { 3  addCandidateEntry(result, candidate, descriptor, requiredType); 4  } 5 }

其中的candidateNames就是構造器中要注入的對象名字indexService和otherIndexService,此處通過循環調用addCandidateEntry來獲取這兩個name對應的bean;

2.2、在DefaultListableBeanFactory的addCandidateEntry方法中,調到了DependencyDescriptor#resolveCandidate方法,在此方法中調用的getBean方法獲取它的成員變量bean。

DependencyDescriptor#resolveCandidate方法如下所示:

1     public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
2             throws BeansException { 3 4 return beanFactory.getBean(beanName); 5 }

 然后又進入了下一次的getBean邏輯。此處就是這樣完成的構造器方法參數注入。

 

    下面進入populateBean中。看源碼經過一個for循環和一個NAME或者TYPE模式的判斷之后,進入了BeanPostProcessor的循環調用中,通過遍歷后置處理器,調用了AutowiredAnnotationBeanPostProcessor#postProcessProperties,也就是一開始我們打斷點的地方,該方法源碼如下:

 1 @Override
 2     public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { 3 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); 4 try { 5  metadata.inject(bean, beanName, pvs); 6  } 7 catch (BeanCreationException ex) { 8 throw ex; 9  } 10 catch (Throwable ex) { 11 throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); 12  } 13 return pvs; 14 }

在第13行打斷點,發現到13行的時候,bean中的屬性已經被注入了,所以可以知道,是在第5行進行的屬性注入。

繼續跟蹤第5行,進入InjectionMetadata#inject方法:

 1 public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
 2         Collection<InjectedElement> checkedElements = this.checkedElements; 3 Collection<InjectedElement> elementsToIterate = 4 (checkedElements != null ? checkedElements : this.injectedElements); 5 if (!elementsToIterate.isEmpty()) { 6 for (InjectedElement element : elementsToIterate) { 7 if (logger.isTraceEnabled()) { 8 logger.trace("Processing injected element of bean '" + beanName + "': " + element); 9  } 10  element.inject(target, beanName, pvs); 11  } 12  } 13 }

 發現是從當前metadata對象中取的element對象,而通過斷點可以看到,checkedElements中的Member對象就是當前bean中加了@Autowired注解的成員變量或者普通方法在反射包中對應的對象,隨后通過element的inject方法進行的注入。那么問題來了,element對象是如何創建來的?inject方法又是如何將bean注入到成員變量中的?

 對於element對象的創建,還要返回postProcessProperties方法中查看上面的findAutowiringMetadata方法:

 1 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
 2         // Fall back to class name as cache key, for backwards compatibility with custom callers.
 3         String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); 4 // Quick check on the concurrent map first, with minimal locking. 5 InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); 6 if (InjectionMetadata.needsRefresh(metadata, clazz)) { 7 synchronized (this.injectionMetadataCache) { 8 metadata = this.injectionMetadataCache.get(cacheKey); 9 if (InjectionMetadata.needsRefresh(metadata, clazz)) { 10 if (metadata != null) { 11  metadata.clear(pvs); 12  } 13 metadata = buildAutowiringMetadata(clazz); 14 this.injectionMetadataCache.put(cacheKey, metadata); 15  } 16  } 17  } 18 return metadata; 19 }

 

 通過斷點到這個方法中,發現此時injectionMetadataCache中已經有了myService對應的InjectionMetadata,此方法只是從map中取出返回。沒辦法了,還要繼續追尋下去,AutowiredAnnotationBeanPostProcessor中的injectionMetadataCache屬性是什么時候觸發的初始化?

在當前類中查詢injectionMetadataCache的put方法,發現只有這一個地方,所以繼續在這里斷點一下,看看什么時候觸發的injectionMetadataCache.put。

 

 發現原來就是在doCreateBean的applyMergedBeanDefinitionPostProcessors方法中觸發的put操作。

下面繼續追尋inject方法中Spring如何完成的屬性注入。

屬性注入進入內部類 AutowiredFieldElement的方法inject中,方法注入進入的是AutowiredMethodElement中。在inject方法中可以看到我們的老朋友DefaultListableBeanFactory#resolveDependency方法,即通過這個方法獲取到對應的bean對象,最后通過反射完成的賦值或方法調用。

這里我們第二次遇到DefaultListableBeanFactory#resolveDependency,發現它是@Autowired注解注入構造器參數、注入成員變量、注入方法參數必經的方法,所以必須繼續搞明白它。

追蹤resolveDependency方法,進入DefaultListableBeanFactory#resolveMultipleBeans方法,該方法屬於@Autowired注解的核心方法,雖然很長,但需要貼出源代碼:

 1 @Nullable
 2     private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
 3             @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
 4 
 5         final Class<?> type = descriptor.getDependencyType();
 6                 // 0、暫時不清楚是做什么用的...
 7         if (descriptor instanceof StreamDependencyDescriptor) {
 8             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
 9             if (autowiredBeanNames != null) {
10                 autowiredBeanNames.addAll(matchingBeans.keySet());
11             }
12             Stream<Object> stream = matchingBeans.keySet().stream()
13                     .map(name -> descriptor.resolveCandidate(name, type, this))
14                     .filter(bean -> !(bean instanceof NullBean));
15             if (((StreamDependencyDescriptor) descriptor).isOrdered()) {
16                 stream = stream.sorted(adaptOrderComparator(matchingBeans));
17             }
18             return stream;
19         }
20         else if (type.isArray()) { // 1、判斷要注入的是不是一個數組,可見除了集合注入外,也可以以數組的形式注入bean
21             Class<?> componentType = type.getComponentType();
22             ResolvableType resolvableType = descriptor.getResolvableType();
23             Class<?> resolvedArrayType = resolvableType.resolve(type);
24             if (resolvedArrayType != type) {
25                 componentType = resolvableType.getComponentType().resolve();
26             }
27             if (componentType == null) {
28                 return null;
29             }
30             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
31                     new MultiElementDescriptor(descriptor));
32             if (matchingBeans.isEmpty()) {
33                 return null;
34             }
35             if (autowiredBeanNames != null) {
36                 autowiredBeanNames.addAll(matchingBeans.keySet());
37             }
38             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
39             Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
40             if (result instanceof Object[]) {
41                 Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
42                 if (comparator != null) {
43                     Arrays.sort((Object[]) result, comparator);
44                 }
45             }
46             return result;
47         }
48         else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { // 2、判斷注入的是不是集合的接口類(List、Set等)
49             Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
50             if (elementType == null) {
51                 return null;
52             }
53             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
54                     new MultiElementDescriptor(descriptor));
55             if (matchingBeans.isEmpty()) {
56                 return null;
57             }
58             if (autowiredBeanNames != null) {
59                 autowiredBeanNames.addAll(matchingBeans.keySet());
60             }
61             TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
62             Object result = converter.convertIfNecessary(matchingBeans.values(), type);
63             if (result instanceof List) {
64                 Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
65                 if (comparator != null) {
66                     ((List<?>) result).sort(comparator);
67                 }
68             }
69             return result;
70         }
71         else if (Map.class == type) { ///3、判斷要注入的是不是map類
72             ResolvableType mapType = descriptor.getResolvableType().asMap();
73             Class<?> keyType = mapType.resolveGeneric(0);
74             if (String.class != keyType) {
75                 return null;
76             }
77             Class<?> valueType = mapType.resolveGeneric(1);
78             if (valueType == null) {
79                 return null;
80             }
81             Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
82                     new MultiElementDescriptor(descriptor));
83             if (matchingBeans.isEmpty()) {
84                 return null;
85             }
86             if (autowiredBeanNames != null) {
87                 autowiredBeanNames.addAll(matchingBeans.keySet());
88             }
89             return matchingBeans;
90         }
91         else { // 4、其他情況返回空,進入doResolveDependency方法做默認處理
92             return null;
93         }
94     }

主要看1/2/3的注釋,可以知道Spring支持多種注入方式就是在這里實現的。我們能發現,在獲取bean的時候都是調用了findAntowireCandidates方法,而且第4中默認的情況,在外部的doResolveDenpency方法中也調用了findAutowireCandidates方法。

至於findAutowireCandidates方法是如何完成的屬性獲取?是通過type還是name獲取到的bean?我們下期繼續!

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM