天天看點

spring依賴注入、屬性填充(源碼分析——中)

這裡我們主要分析spring是怎麼去根據類型或name去找值得。

方法參數的名字:加了@Autowired 注解的方法中的參數

字段:加了@Autowired的屬性

spring依賴注入、屬性填充(源碼分析——中)
spring依賴注入、屬性填充(源碼分析——中)
DependencyDescriptor descriptor           

descriptor可能是字段,也可能是方法的參數,需要根據descriptor來擷取(字段或方法參數)的名字或類型。

descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());           

上面這段代碼主要是為了擷取方法參數的名字。

spring依賴注入、屬性填充(源碼分析——中)

1

spring依賴注入、屬性填充(源碼分析——中)

2

spring依賴注入、屬性填充(源碼分析——中)

3

spring依賴注入、屬性填充(源碼分析——中)

4

addDiscoverer(new StandardReflectionParameterNameDiscoverer());
addDiscoverer(new LocalVariableTableParameterNameDiscoverer());           

這裡初始化了兩種擷取方法參數的名字,一種是基于反射:主要是jdk1.8以上提供的方法。一種是基于本地變量表,主要是解決jdk1.7 沒有通過反射可以擷取方法參數名字的問題。

1.@Autowired+@Lazy

spring依賴注入、屬性填充(源碼分析——中)

懶注入

Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
      descriptor, requestingBeanName);           

上面這段代碼就是處理@Lazy注解:

如果加了@Lazy注解 那麼就會傳回一個代理對象,将代理對象指派給屬性(方法參數)。當屬性(方法參數)在調用方法的時候,spring才會去找bean。

2.@Value

spring依賴注入、屬性填充(源碼分析——中)
spring依賴注入、屬性填充(源碼分析——中)

處理@Value

String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
      getMergedBeanDefinition(beanName) : null);           

這段代碼是處理這種方式指派:@Value(${"456"})

spring在最開始的時候會初始化一個Environment ,這個對象裡面包含了spring.properties 配置檔案中的key value 鍵值對.

@Value注解就是去Environment 對象中根據鍵找值。

value = evaluateBeanDefinitionString(strVal, bd);           

這個是為了處理:@Value("#{person}")

這種是spring表達式,可以根據person 這個名字從spring容器中找bean 給屬性指派。

3.屬性定義為:Map<String,Person> person

spring依賴注入、屬性填充(源碼分析——中)
spring依賴注入、屬性填充(源碼分析——中)

這種情況,spring會根據類型去找值,找到之後會将bean 的名字作為key, 值作為value 存入到map中。 這裡map 的key 隻能是string。

4.拿到符合類型的bean 或 beanClass

spring依賴注入、屬性填充(源碼分析——中)

這裡拿到的可能是bean對象,也可能是 beanClass。

spring依賴注入、屬性填充(源碼分析——中)
spring依賴注入、屬性填充(源碼分析——中)
spring依賴注入、屬性填充(源碼分析——中)

如上面兩個圖,同一個類型(Company)的bean 有兩個,名字不一樣。那麼擷取的時候不管是建立好了對象,還是沒建立好,都可以通過beanDefinition來判斷是不是符合該類型。

如果判斷是同類型,那麼就會存到map中,在存的時候如果建立好就會存bean對象,如果沒有建立好就會存beanClass。

5.1通過名字來進行比對

spring依賴注入、屬性填充(源碼分析——中)

如果是多個,這裡會根據名字來進行比對。 但是這裡是有一個優先級的。順序如下:

@Primary > @Primary(1)>name

5.2 處理根據類型擷取單個bean 。

spring依賴注入、屬性填充(源碼分析——中)

6.記錄beanName

spring依賴注入、屬性填充(源碼分析——中)

7.如果擷取的是bean的類型 ,那就進行執行個體化

spring依賴注入、屬性填充(源碼分析——中)

8.處理null

spring依賴注入、屬性填充(源碼分析——中)
spring依賴注入、屬性填充(源碼分析——中)

如上圖所示 定義一個bean 傳回null, 那麼spring 在存的時候,會以com 為key , nullBean 為值:map<com,nullBean>