這裡我們主要分析spring是怎麼去根據類型或name去找值得。
方法參數的名字:加了@Autowired 注解的方法中的參數
字段:加了@Autowired的屬性
DependencyDescriptor descriptor
descriptor可能是字段,也可能是方法的參數,需要根據descriptor來擷取(字段或方法參數)的名字或類型。
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
上面這段代碼主要是為了擷取方法參數的名字。
1
2
3
4
addDiscoverer(new StandardReflectionParameterNameDiscoverer());
addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
這裡初始化了兩種擷取方法參數的名字,一種是基于反射:主要是jdk1.8以上提供的方法。一種是基于本地變量表,主要是解決jdk1.7 沒有通過反射可以擷取方法參數名字的問題。
1.@Autowired+@Lazy
懶注入
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
上面這段代碼就是處理@Lazy注解:
如果加了@Lazy注解 那麼就會傳回一個代理對象,将代理對象指派給屬性(方法參數)。當屬性(方法參數)在調用方法的時候,spring才會去找bean。
2.@Value
處理@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會根據類型去找值,找到之後會将bean 的名字作為key, 值作為value 存入到map中。 這裡map 的key 隻能是string。
4.拿到符合類型的bean 或 beanClass
這裡拿到的可能是bean對象,也可能是 beanClass。
如上面兩個圖,同一個類型(Company)的bean 有兩個,名字不一樣。那麼擷取的時候不管是建立好了對象,還是沒建立好,都可以通過beanDefinition來判斷是不是符合該類型。
如果判斷是同類型,那麼就會存到map中,在存的時候如果建立好就會存bean對象,如果沒有建立好就會存beanClass。
5.1通過名字來進行比對
如果是多個,這裡會根據名字來進行比對。 但是這裡是有一個優先級的。順序如下:
@Primary > @Primary(1)>name
5.2 處理根據類型擷取單個bean 。
6.記錄beanName
7.如果擷取的是bean的類型 ,那就進行執行個體化
8.處理null
如上圖所示 定義一個bean 傳回null, 那麼spring 在存的時候,會以com 為key , nullBean 為值:map<com,nullBean>