由于之前為公司的rpc中間件加了一個@Provider的注解,注解中需要為provider添加一個別名,類似dubbo里面的version,之前寫這個@Provider實現(xiàn)時并未讓別名字段支持@Value里面那種${}占位符轉(zhuǎn)換配置文件屬性的功能,導致今天在使用時,無法實現(xiàn)不同環(huán)境不同別名的功能,所以這個必須安排上呀,開搞!
@Value是如何實現(xiàn)${}占位符綁定配置文件參數(shù)的呢
我們先點開Value這個注解

一大堆的文檔,我們可以看到,文檔告訴我們應(yīng)該去查看AutowiredAnnotationBeanPostProcessor這個類的實現(xiàn),繼續(xù)點開
查看源碼,我們可以看到這個類會處理Autowired,Value,Inject三個注解,都是在類實例化時添加進去的,后面我們需要自己實現(xiàn)參數(shù)注入時就會用到這個

上面Value的文檔有告訴我們參數(shù)注入是通過BeanPostProcessor來實現(xiàn)的,同時我們可以看到AutowiredAnnotationBeanPostProcessor繼承了InstantiationAwareBeanPostProcessorAdapter這個適配器,而InstantiationAwareBeanPostProcessorAdapter實現(xiàn)了SmartInstantiationAwareBeanPostProcessor接口,而SmartInstantiationAwareBeanPostProcessor又繼承了InstantiationAwareBeanPostProcessor接口
ps: 我記得低版本的springboot這里是直接實現(xiàn)的InstantiationAwareBeanPostProcessor接口,之前找過一次,記不清楚了,有可能記錯了



查看InstantiationAwareBeanPostProcessor接口的文檔,我們可以看到postProcessProperties和postProcessPropertyValues兩個方法都是在給對象屬性復制后回調(diào)的,但是postProcessPropertyValues方法已被棄用了,到這里,我們就找到Value和Autowired注入的時間點了

回到AutowiredAnnotationBeanPostProcessor類,找到其實現(xiàn)的postProcessProperties方法,這里也就是參數(shù)注入的觸發(fā)點了,這里同時實現(xiàn)了上面的兩個方法

這個方法比較簡單(簡單是因為我們跳過了findAutowiringMetadata這個查找的過程,自己研究去吧),就是查到到所有需要自動注入的屬性,調(diào)用注入方法,我們繼續(xù)點開metadata.inject方法

可以看到這個方法是遍歷上步找到的屬性,挨個調(diào)用inject方法,我們繼續(xù)點開inject方法

點開后,我們可以看到idea有提示我們哪里重寫了這個方法,點擊這個提示,我們又回到了AutowiredAnnotationBeanPostProcessor類,同時我們可以看到這個類中有兩個內(nèi)部類都繼承了InjectionMetadata.InjectedElement并重寫了inject方法

看文檔我們可以知道第一個是注入屬性的,第二個是實現(xiàn)方法上的數(shù)據(jù)注入的,到這里我們就找到數(shù)據(jù)注入的點了,接下來我們給inject方法打個斷點,我們?nèi)フ艺嘉环D(zhuǎn)換的代碼
對了,你還得寫個啟動demo

一步一步斷點之后,當走到這步時,我發(fā)現(xiàn)數(shù)據(jù)已經(jīng)變成我配置文件中的值了,那數(shù)據(jù)轉(zhuǎn)換就是在下面這步完成的
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

重新斷點進beanFactory.resolveDependency這個方法,我們發(fā)現(xiàn)數(shù)據(jù)是在箭頭指向的那一行發(fā)生的變化,重新再跑一次debug,進入doResolveDependency方法

這時候拿到的還是占位符,繼續(xù)

到這里,我們發(fā)現(xiàn)數(shù)據(jù)已經(jīng)被轉(zhuǎn)換的,后面的不走我這里也就不走了,因為我這次的目的是找到占位符的解析代碼,這里簡單的說下后續(xù)代碼
value = evaluateBeanDefinitionString(strVal, bd);
這一步是在處理el表達式,就是#{}包裹的數(shù)據(jù)
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
這一步則是在返回數(shù)據(jù)前對數(shù)據(jù)做一次轉(zhuǎn)換,比如把String轉(zhuǎn)成int,就是將原始數(shù)據(jù)轉(zhuǎn)為需要注入的屬性需要的類型數(shù)據(jù)
回到正題,我們繼續(xù)點開resolveEmbeddedValue方法,發(fā)現(xiàn)這個方法是AbstractBeanFactory的一個公開方法,而DefaultListableBeanFactory也有繼承AbstractBeanFactory

因為我之前實現(xiàn)@Provider注解時,是通過實現(xiàn)BeanFactoryPostProcessor接口實現(xiàn)的,所以我這里可以拿到DefaultListableBeanFactory對象,所以我直接調(diào)用resolveEmbeddedValue方法就可以啦
到此,@Provider完美搞定占位符解析,可以愉快的用配置文件實現(xiàn)不同環(huán)境不同別名啦