前言
閱讀準(zhǔn)備
由于Spring源碼分析是一個前后聯(lián)系比較強的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序):
- Spring底層核心原理解析【學(xué)習(xí)難度:★★☆☆☆】
- 手寫簡易Spring容器過程分析【學(xué)習(xí)難度:★★☆☆☆】
- Spring之底層架構(gòu)核心概念解析【學(xué)習(xí)難度:★★★☆☆,重要程度:★★★★★】
- Bean的生命周期流程圖【學(xué)習(xí)難度:☆☆☆☆☆,重要程度:★★★★★】
- Spring之Bean的生命周期源碼解析——階段一(掃描生成BeanDefinition)【學(xué)習(xí)難度:★★☆☆☆,重要程度:★★★☆☆】
- Spring之Bean的生命周期源碼解析——階段二(IOC之實例化)【學(xué)習(xí)難度:★★★★★,重要程度:★★★☆☆】
(PS:特別是《Bean的生命周期流程圖》,幫大家【開天眼】,先了解下流程。畢竟【通過業(yè)務(wù)了解代碼,遠(yuǎn)比通過代碼了解業(yè)務(wù)簡單的多】?。。。。?/mark>
(PS:特別是《Bean的生命周期流程圖》,幫大家【開天眼】,先了解下流程。畢竟【通過業(yè)務(wù)了解代碼,遠(yuǎn)比通過代碼了解業(yè)務(wù)簡單的多】?。。。。?/mark>
(PS:特別是《Bean的生命周期流程圖》,幫大家【開天眼】,先了解下流程。畢竟【通過業(yè)務(wù)了解代碼,遠(yuǎn)比通過代碼了解業(yè)務(wù)簡單的多】!?。。。?/mark>
閱讀指引
我們在上一節(jié)課已經(jīng)說到過了,本次Spring源碼剖析的總?cè)肟谑?code>new AnnotationConfigApplicationContext("org.tuling.spring");,這里就不再重復(fù)解釋了。本節(jié)課要說的內(nèi)容,是SpringIOC的屬性填充/依賴注入,我們這里直接給到入口吧,調(diào)用鏈如下:(調(diào)用鏈比較深,不要糾結(jié)細(xì)枝末節(jié))
- AbstractApplicationContext#refresh:刷新方法,不用在意
- AbstractApplicationContext#finishBeanFactoryInitialization:在這里實例化所有剩余的(非lazy-init)單例
- DefaultListableBeanFactory#preInstantiateSingletons:在這里實例化所有剩余的(非lazy-init)單例(上面的方法,核心干活的方法就是這里)
- DefaultListableBeanFactory#getBean:獲取Bean的方法
- AbstractBeanFactory#doGetBean:返回指定bean的一個實例,它可以是共享的,也可以是獨立的
- 上面這個
AbstractBeanFactory#doGetBean
里面的一段局部代碼寫的回調(diào)方法,如下:
// 如果是單例創(chuàng)建bean實例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
- AbstractAutowireCapableBeanFactory#createBean:這個類的中心方法:創(chuàng)建一個bean實例,填充bean實例,應(yīng)用后處理器,等等。
- AbstractAutowireCapableBeanFactory#doCreateBean:【實例化】及后面聲明周期調(diào)用地方。
- 【入口一】:AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors:應(yīng)用合并BeanDefinition后置處理器給給定的BeanDefinition。
- 【入口二】AbstractAutowireCapableBeanFactory#populateBean:使用來自bean定義的屬性值在給定的BeanWrapper中填充bean實例。
如上面的調(diào)用鏈所示,最后兩個方法,才是我們本次要研究的核心方法。為什么這里會說有兩個入口呢?主要是,本章的【屬性填充/依賴注入】將分為兩個部分來解析?!救肟谝弧繉?yīng)的是【第一部分:尋找注入點】;【入口二】對應(yīng)的是【第二部分:屬性填充及填充后】
閱讀建議
- 看源碼,切記糾結(jié)細(xì)枝末節(jié),不然很容易陷進(jìn)去。正常來說,看主要流程就好了
- 遇到不懂的,多看看類注釋或者方法注釋。Spring這種優(yōu)秀源碼,注釋真的非常到位
- 如果你是idea用戶,多用F11的書簽功能。
- Ctrl + F11 選中文件 / 文件夾,使用助記符設(shè)定 / 取消書簽 (必備)
- Shift + F11 彈出書簽顯示層 (必備)
- Ctrl +1,2,3…9 定位到對應(yīng)數(shù)值的書簽位置 (必備)
閱讀導(dǎo)航
系列上一篇文章:《【Spring專題】Spring之Bean的生命周期源碼解析——階段二(一)(IOC之實例化)》
系列下一篇文章:《【Spring專題】Spring之Bean的生命周期源碼解析——階段二(三)(屬性填充之循環(huán)依賴底層原理解析)》
課程內(nèi)容
一、依賴注入方式(前置知識)
在Spring中,屬性注入的方式分為兩種,分別是:【手動注入】和【自動注入】。
1.1 手動注入
在XML中定義Bean時,就是手動注入,因為是程序員手動給某個屬性指定了值。如下:
<bean name="userService" class="com.luban.service.UserService">
<property name="orderService" ref="orderService"/>
</bean>
有經(jīng)驗的同學(xué)應(yīng)該知道,上面這種底層是通過setXxx
方法進(jìn)行注入的。另外,還有一種方式,是通過構(gòu)造方法進(jìn)行注入的,如下:
<bean name="userService" class="com.luban.service.UserService">
<constructor-arg index="0" ref="orderService"/>
</bean>
所以手動注入的底層也就是分為兩種:【set方法注入】和【構(gòu)造方法注入】。
1.2 自動注入
自動注入又分為兩種:【XML的autowire自動注入】和【@Autowired注解的自動注入】。
1.2.1 XML的autowire自動注入
在XML中,我們可以在定義一個Bean時去指定這個Bean的自動注入模式,它有如下幾種方式:
1.2.1.1 byType:按照類型進(jìn)行注入
byType注入方式,底層是基于setXxx
方法實現(xiàn)的,所以setter方法不能少。這里說的類型是【入?yún)ⅰ康念愋汀?br> Spring在通過byType的自動填充屬性時流程是:
- 獲取到set方法中的唯一參數(shù)的參數(shù)類型,并且根據(jù)該類型去容器中獲取bean
- 如果找到多個,會報錯
使用示例如下:
<bean id="userService" class="com.luban.service.UserService" autowire="byType"/>
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
如上示例的類型,就是指入?yún)?code>orderService的類型OrderService
1.2.1.2 byName:按照名稱進(jìn)行注入
byType注入方式,底層是基于setXxx
方法實現(xiàn)的,所以setter方法不能少。這里說的【名稱】,是指setXxx
后面的Xxx
部分。
所以,Spring在通過byName的自動填充屬性時流程是:
- 找到所有set方法所對應(yīng)的Xxx部分的名字
- 根據(jù)Xxx部分的名字去獲取bean
使用示例如下:
<bean id="userXmlBean" class="org.tuling.spring.xml.bean.UserXmlBean" autowire="byName"/>
<bean id="walletXmlBean" class="org.tuling.spring.xml.bean.WalletXmlBean"/>
如上,我們定義了userXmlBean
的自動注入類型是byName
,并且定義了一個名字叫walletXmlBean
的bean。
public class UserXmlBean {
private WalletXmlBean wallet;
public void printProperty() {
System.out.println(wallet);
}
public void setWalletXmlBean(WalletXmlBean param) {
this.wallet = param;
}
}
如上,我們定義了一個UserXmlBean
,他有成員變量WalletXmlBean wallet
。同時給他聲明了一個成員方法printProperty()
用來打印它的成員屬性的地址。
測試代碼:
public class MyXmlApplicationContextTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserXmlBean userXmlBean = (UserXmlBean)context.getBean("userXmlBean");
userXmlBean.printProperty();
}
// 系統(tǒng)輸出:
// org.tuling.spring.xml.bean.WalletXmlBean@1d16f93d
}
如上,UserXmlBean
的WalletXmlBean
類型的屬性出現(xiàn)了2個名稱,一個是成員變量wallet
,另一個是setter方法入?yún)⒅械?code>param,但是一點都不妨礙我們byName
注入。因為,根據(jù)byName
的規(guī)則,尋找的是setXxx
后面的Xxx
部分。還不夠信服是嗎?我們改一下UserXmlBean
里面的setter方法,如下:
public void setWalletXmlBean123(WalletXmlBean param) {
this.wallet = param;
}
這個時候再去調(diào)用,輸出null
。
1.2.1.3 constructor:按照構(gòu)造方法進(jìn)行注入
constructor表示通過構(gòu)造方法注入,其實這種情況就比較簡單了,沒有byType和byName那么復(fù)雜。
如果是constructor,那么就可以不寫set方法了,當(dāng)某個bean是通過構(gòu)造方法來注入時,spring利用構(gòu)造方法的參數(shù)信息從Spring容器中去找bean,找到bean之后作為參數(shù)傳給構(gòu)造方法,從而實例化得到一個bean對象,并完成屬性賦值(屬性賦值的代碼得程序員來寫)。
(PS:我們這里先不考慮一個類有多個構(gòu)造方法的情況,后面單獨講推斷構(gòu)造方法。我們這里只考慮只有一個有參構(gòu)造方法。)
其實構(gòu)造方法注入相當(dāng)于byType+byName。Spring在通過byName的自動填充屬性時流程是:
- 通過構(gòu)造方法中的參數(shù)類型去找bean,如果對應(yīng)的類型只有一個bean,那就是它了;
- 如果找到多個會根據(jù)參數(shù)名確定
- 如果最后根據(jù)參數(shù)名都無法確定,則報錯
使用示例如下:
<bean id="userXmlBean" class="org.tuling.spring.xml.bean.UserXmlBean" autowire="constructor"/>
<bean id="walletXmlBean123" class="org.tuling.spring.xml.bean.WalletXmlBean"/>
<bean id="walletXmlBean" class="org.tuling.spring.xml.bean.WalletXmlBean"/>
bean示例:
public class UserXmlBean {
private WalletXmlBean wallet;
public void printProperty() {
System.out.println(wallet);
}
public UserXmlBean(WalletXmlBean walletXmlBean) {
this.wallet = walletXmlBean;
}
}
具體的調(diào)用跟錯誤方式這邊就不介紹了,大家回頭自己試試吧
1.2.1.4 其他
其他,諸如:
- default:表示默認(rèn)值,我們一直演示的某個bean的autowire,而也可以直接在<beans>標(biāo)簽中設(shè)置autowire,如果設(shè)置了,那么<bean>標(biāo)簽中設(shè)置的autowire如果為default,那么則會用<beans>標(biāo)簽中設(shè)置的autowire
- no:表示關(guān)閉autowire,不自動注入
1.2.1.5 XML的autowire自動注入方式總結(jié)
那么XML的自動注入底層其實也就是:
- set方法注入
- 構(gòu)造方法注入
1.2.2 @Autowired注解的自動注入
@Autowired注解,本質(zhì)上也是byType和byName的結(jié)合。它是先byType,如果找到多個則byName。這個跟xml構(gòu)造方式注入原理如出一轍。就是:
- 先根據(jù)類型去找bean,如果對應(yīng)的類型只有一個bean,那就是它了;
- 如果找到多個會根據(jù)屬性名確定
- 如果最后根據(jù)屬性名都無法確定,則報錯
@Autowired注解可以寫在:
- 屬性上:先根據(jù)屬性類型去找Bean,如果找到多個再根據(jù)屬性名確定一個(屬性注入)
- 構(gòu)造方法上:先根據(jù)方法參數(shù)類型去找Bean,如果找到多個再根據(jù)參數(shù)名確定一個(構(gòu)造方法注入)
- set方法上:先根據(jù)方法參數(shù)類型去找Bean,如果找到多個再根據(jù)參數(shù)名確定一個(set方法注入)
1.2.3 自動注入總結(jié)
可以發(fā)現(xiàn)XML中的自動注入是挺強大的,那么問題來了,為什么我們平時都是用的@Autowired注解呢?而沒有用上文說的這種自動注入方式呢?
其實啊,@Autowired注解相當(dāng)于XML中的autowire屬性的注解方式的替代。從本質(zhì)上講,@Autowired注解提供了與autowire相同的功能,但是擁有更細(xì)粒度的控制和更廣泛的適用性。
XML中的autowire控制的是整個bean的所有屬性,而@Autowired注解是直接寫在某個屬性、某個set方法、某個構(gòu)造方法上的。
再舉個例子,如果一個類有多個構(gòu)造方法,那么如果用XML的autowire=constructor,你無法控制到底用哪個構(gòu)造方法,而你可以用@Autowired注解來直接指定你想用哪個構(gòu)造方法。
同時,用@Autowired注解,還可以控制,哪些屬性想被自動注入,哪些屬性不想,這也是細(xì)粒度的控制。
二、依賴注入過程
2.1 簡單回顧
依賴注入的過程,大體上其實能分為以下三步的:【尋找注入點】、【填充屬性】、【填充屬性后】。但其實,【尋找注入點】這個過程,會在兩個地方被調(diào)用。第一個就是箭頭所向,【實例化】階段【BeanDefinition后置處理】那個地方。怎么理解呢?因為,【尋找注入點】的實現(xiàn)類就是【BeanDefinition后置處理】中的一個。
上面說的概念多少有點繞。簡單來說,【尋找注入點】就是尋找被@Autowird
、@Value
、@Inject
、@Resource
注解修飾的屬性、方法等等;然后,【屬性填充】的時候再來處理這些找到的注入點,將他們設(shè)置到對應(yīng)Bean屬性中。
2.2 概念回顧
在這個【實例化】過程中,涉及到了一些Spring底層設(shè)計的概念,我在上一個筆記里面有大概介紹過Spring底層概念的一些講解,不記得的同學(xué)記得回去翻一翻。
主要涉及的概念有:
- BeanDefinition(設(shè)計圖紙):BeanDefinition表示Bean定義,BeanDefinition中存在很多屬性用來描述一個Bean的特征
-
MergedBeanDefinitionPostProcessor:合并BeanDefinition后置處理器。但這里其實主要說的是
AutowiredAnnotationBeanPostProcessor
跟CommonAnnotationBeanPostProcessor
。他倆有什么作用呢?前者是處理Spring內(nèi)部定義的@Autowired
跟@Value
自動注入注解;后者是處理jdk定義的@Resource
注解。主要是用到了這個MergedBeanDefinitionPostProcessor
的postProcessMergedBeanDefinition
去完成【尋找注入點】的操作 -
InstantiationAwareBeanPostProcessor:感知實例化的Bean后置處理器。這個也是跟上面一樣,其實主要說的也是
AutowiredAnnotationBeanPostProcessor
跟CommonAnnotationBeanPostProcessor
。這兩個類也繼承了InstantiationAwareBeanPostProcessor
,并且在里面的postProcessProperties
完成了對應(yīng)注解【自動注入】的操作
CommonAnnotationBeanPostProcessor
接口定義如下:
/**
* 這個后置處理器通過繼承InitDestroyAnnotationBeanPostProcessor和InstantiationAwareBeanPostProcessor注解,
* 獲得了對@PostConstruct和@PreDestroy的支持。
* 另外,這個類的核心處理元素是@Resource注解
*/
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
// 具體代碼就不貼了。學(xué)到這里大家應(yīng)該知道如何通過【接口】繼承、實現(xiàn)來猜測類能力了吧
}
AutowiredAnnotationBeanPostProcessor
接口定義如下:
// 繼承類跟CommonAnnotationBeanPostProcessor 如出一轍,唯一不同的是,繼承了功能更強大的
// SmartInstantiationAwareBeanPostProcessor(InstantiationAwareBeanPostProcessor子類)
// 實現(xiàn)這個類,是為了實現(xiàn)里面的推斷構(gòu)造方法
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
2.3 核心方法講解
本節(jié)【屬性注入】,將會分兩個部分來講。第一部分是:【尋找注入點】;剩下的是第二部分。
先說第一部分,第一部分主要涉及【3個類,7個核心方法】。
第二部分,待定…
三、【尋找注入點】方法講解
我在上面說過,【尋找注入點】其實是有兩個地方會調(diào)用到的。一個是在【屬性填充populateBean()
】之前的【合并BeanDefinitionapplyMergedBeanDefinitionPostProcessors()
】,另一個就是在【屬性填充】里面了。(【尋找注入點】源碼以AutowiredAnnotationBeanPostProcessor舉例)
3.1 AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors:尋找注入點代碼入口
全路徑:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors
將MergedBeanDefinitionPostProcessors應(yīng)用于指定的bean定義,調(diào)用它們的postProcessMergedBeanDefinition方法。
源碼如下:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
我們點開這個循環(huán)的類對象,找到他們的兩個實現(xiàn)類:AutowiredAnnotationBeanPostProcessor
和CommonAnnotationBeanPostProcessor
。為了方便,我們這里就只舉例AutowiredAnnotationBeanPostProcessor
,因為他倆實現(xiàn)方式基本雷同,只不過前者處理的Spring的注解,由Spring本家寫的;后者處理的JDK的注解。
3.2 AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
方法調(diào)用鏈:由3.2的applyMergedBeanDefinitionPostProcessors()調(diào)用進(jìn)來
全路徑:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
方法注釋:對指定bean的給定合并bean定義進(jìn)行后處理。
源碼如下:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
方法解讀:代碼很簡單,整個過程真正干活的其實是里面的findAutowiringMetadata()
方法
3.3 AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata:尋找注入點
方法調(diào)用鏈:由3.2的applyMergedBeanDefinitionPostProcessors()調(diào)用進(jìn)來
全路徑:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
方法注釋:尋找注入點
** private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// 設(shè)置緩存key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 先看緩存里面有沒有
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}**
方法解讀:在這里,用到了一個緩存,說白了就是一個map,來判斷是否已經(jīng)【尋找過注入點】了,也是為了方便后續(xù)做注入。在這里,最核心的操作還是通過調(diào)用buildAutowiringMetadata
,構(gòu)建了當(dāng)前類的注入點信息,并且包裝成了InjectionMetadata
。
*3.4 AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata:構(gòu)建注入點
方法調(diào)用鏈:由3.3的findAutowiringMetadata()調(diào)用進(jìn)來
全路徑:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
方法注釋:構(gòu)建注入點
源碼如下:
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
// 第一步:判斷當(dāng)前類是否候選類(是否需要【尋找注入點】)
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 第二步:利用反射,尋找【字段】上是否有【自動注入】的注解
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
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))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
方法解讀:上面的方法看似很長,但整體上就分為三個步驟而已,沒什么特別難理解的地方。特別是,如果你如果看過我前面的【手寫Spring-引導(dǎo)篇】的話。
第一個步驟,判斷當(dāng)前類是否候選類(是否需要【尋找注入點】)。說實在這里暫時不確定啥意思,看代碼就是過濾java.
開頭的類跟注解(百度了下,java.開頭的一般是JDK開放的API,其中元注解就在里面聲明,如:@Retention、@Target等)。所以我的理解是,這里的判斷邏輯是讓Spring的類,或者說我們自定義的類,可以使用JDK的【自動裝配】注解,比如@Resource;但是JDK只能用JDK自己的【自動裝配】注解。
第二個步驟:我們都知道,@Autowired
注解,可以修飾在字段和方法上的,第二個步驟就是處理【字段】類型的注解。
第三個步驟:處理【方法】類型的注解。
關(guān)于第二、三步的源碼實現(xiàn)其實都一樣,只不過處理對象不一樣而已,所以這里就只拿處理【字段】的邏輯來講講了。即如下:
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
不過還是要先說一點。大家可能注意到了,這整個處理是在一個do-while
循環(huán)體里面完成的,為什么呢?其實這里的do-while
循環(huán)就是為了處理存在【繼承關(guān)系的Bean】的注入而已。
3.5 ReflectionUtils#doWithLocalFields:利用反射遍歷類上的【字段】
方法調(diào)用鏈:由3.4的buildAutowiringMetadata()調(diào)用進(jìn)來
全路徑:org.springframework.util.ReflectionUtils#doWithLocalFields
方法注釋:對給定類中所有局部聲明的字段調(diào)用給定的回調(diào)。
反射工具方法實現(xiàn)如下:
public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
for (Field field : getDeclaredFields(clazz)) {
try {
fc.doWith(field);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
}
}
}
(PS:這上邊的代碼,如果對函數(shù)式接口,或者說lambda表達(dá)式使用不清楚的可能看不懂,得趕緊去復(fù)習(xí)下了)
3.6 AutowiredAnnotationBeanPostProcessor#findAutowiredAnnotation:尋找字段上的自動裝配注解
方法調(diào)用鏈:由3.5的doWithLocalFields()調(diào)用進(jìn)來
全路徑:org.springframework.util.ReflectionUtils#doWithLocalFields
方法注釋:對給定類中所有局部聲明的字段調(diào)用給定的回調(diào)。
再然后,就是在反射【回調(diào)函數(shù)】里面,調(diào)用findAutowiredAnnotation
判斷當(dāng)前字段、方法是否有【自動裝配】的注解。如下:
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
細(xì)心的朋友可能會問了, this.autowiredAnnotationTypes
的值是啥?是的,我知道是@Autowired
和@Value
注解,但是在哪里賦值呢?啊,這個目前不會講到,這是在Spring容器啟動的章節(jié)才會給大家講。但是可以先告訴大家,這個是在AutowiredAnnotationBeanPostProcessor
的構(gòu)造方法中初始化的。如下:
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
3.7 Modifier.isStatic
方法調(diào)用鏈:由3.5的doWithLocalFields()調(diào)用進(jìn)來
全路徑:java.lang.reflect.Modifier#isStatic
方法注釋:對給定類中所有局部聲明的字段調(diào)用給定的回調(diào)。
然后,如果找到有被@Autowired和@Value注解的字段或者方法,還會判斷該字段或者方法是否被static
修飾,即靜態(tài)的。靜態(tài)的就不處理了。源碼如下:
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
點解?。康览砗芎唵蔚?,你從原型Bean考慮一下就知道了。我們知道靜態(tài)的是屬于類的,不是屬于對象的,那如果你每次注入的時候還要處理靜態(tài),那不就重復(fù)覆蓋了嗎?舉例:
@Component
@Scope("prototype")
public class OrderService {
}
@Component
@Scope("prototype")
public class UserService {
@Autowired
private static OrderService orderService;
public void test() {
System.out.println("test123");
}
}
看上面代碼,UserService和OrderService都是原型Bean,假設(shè)Spring支持static字段進(jìn)行自動注入,那么現(xiàn)在調(diào)用兩次
UserService userService1 = context.getBean("userService")
UserService userService2 = context.getBean("userService")
問此時,userService1的orderService值是什么?還是它自己注入的值嗎?答案是不是,一旦userService2 創(chuàng)建好了之后,static orderService字段的值就發(fā)生了修改了,從而出現(xiàn)bug。
3.8 剩余步驟
剩余步驟,干了三件事,如下:
- 設(shè)置
@Autowired(required = false)
這個屬性 - 將得到構(gòu)建點包裝成
InjectionMetadata.InjectedElement
- 將得到的所有注入點,封裝成
InjectionMetadata
,接著緩存起來
四、【尋找注入點】邏輯流程圖
流程描述:
- 遍歷當(dāng)前類的所有的屬性字段Field
- 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一個,存在則認(rèn)為該字段是一個注入點
- 如果字段是static的,則不進(jìn)行注入
- 獲取@Autowired中的required屬性的值
- 將字段信息構(gòu)造成一個AutowiredFieldElement對象,作為一個注入點對象添加到currElements集合中。
- 遍歷當(dāng)前類的所有方法Method
- 判斷當(dāng)前Method是否是橋接方法,如果是找到原方法
- 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一個,存在則認(rèn)為該方法是一個注入點
- 如果方法是static的,則不進(jìn)行注入
- 獲取@Autowired中的required屬性的值
- 將方法信息構(gòu)造成一個AutowiredMethodElement對象,作為一個注入點對象添加到currElements集合中。
- 遍歷完當(dāng)前類的字段和方法后,將遍歷父類的,直到?jīng)]有父類。
- 最后將currElements集合封裝成一個InjectionMetadata對象,作為當(dāng)前Bean對于的注入點集合對象,并緩存。
四點五、特別聲明
兄弟們,提前聲明一下,下面的內(nèi)容個人感覺特別復(fù)雜,是我按照Spring源碼閱讀順序以來,目前最復(fù)雜的一部分。不過也由于分了兩個部分,層次感還是有的,所以大家如果是在沒有繼續(xù)看下去的欲望了,剩下的下次再看吧。[/狗頭][/狗頭]
所以,我想著,在后面的講解中,換一種方式來寫寫。
- 首先,我會先給出流程圖,并且按照樹形結(jié)構(gòu)的方式寫
- 其次,我將按照源碼調(diào)用次序,【自上而下、從左往右】的方式映射到樹形結(jié)構(gòu)上
- 最后到了這里,我感覺大家需要打開Spring源碼,一邊看文章,一邊看源碼的方式來閱讀了
- 我并不會講解所有的源碼,只會將一些比較陌生、或者關(guān)鍵的源碼點一下
五、【屬性填充】邏輯流程圖
整體源碼邏輯流程圖如下:(畫的我吐血)
圖片點開來很不清晰,建議大家:右鍵、新建窗口打開。 然后就可以放大觀看了
六、【屬性填充】方法講解
我們在【閱讀建議】中已經(jīng)說過【入口二】是AbstractAutowireCapableBeanFactory#populateBean
。在這個方法,我們在上面屬性流程圖畫的第一二層,講的就是這個方法。
6.1 AbstractAutowireCapableBeanFactory#populateBean
全路徑:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
方法解釋:使用來自bean定義的屬性值在給定的BeanWrapper中填充bean實例。
對應(yīng)流程圖:
源碼如下:(標(biāo)記了步驟一、二、三才是本章研究內(nèi)容)
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 空判斷,有屬性,但是bean為空,則報錯
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// 這個在之前的【實例化階段】的【實例化后】講過了,不在本次研究范圍內(nèi)
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
// 下面才是我們本節(jié)課要研究的起點
// 下面才是我們本節(jié)課要研究的起點
// 下面才是我們本節(jié)課要研究的起點
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 步驟一:
// 處理beanDefinition的autowire屬性。比如@Bean標(biāo)簽就可以設(shè)置這個屬性;xml也可以設(shè)置這個屬性
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 步驟二:
// 處理@Autowired、@Value、@Resource等【自動注入】的屬性填充(注意,之前是尋找注入點,這里才是真正賦值的地方)
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
// 依賴檢查,【細(xì)枝末節(jié)】,不看了
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 步驟三:
// 處理BeanDefinition里面的propertyValues。比如:我們在操作beanDefinition的時候會修改;
// 或者,在第一步處理@Bean的autowire屬性的時候,實際上也是把結(jié)果跟舊有BeanDefinition的propertyValues合并。
// 最后在這里處理注入操作
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
方法解讀:方法看著很長,但其實邏輯還算是比較清晰的。只不過有點可惜的是,感覺代碼風(fēng)格突然變了,跟前面研究的方法明顯出于不同之人。比如,在之前,populateBean()
里面德的【處理實例化后】階段源碼,會搞個resolveAfterInstantiation()
方法來封裝起來;步驟一也會寫成一個resolveAutowireMode()
方法,語義會更加清晰點。唉,后面這樣寫,多少給源碼閱讀增添了點難受。
廢話不多說了,我們分析里面的流程吧。
- 步驟一:主要是處理@Bean這個標(biāo)簽的
autowire
屬性。其實嚴(yán)格來說,是處理beanDefinition下的autowire
屬性。估計大家沒怎么用過,如下:
@Bean(autowire = Autowire.BY_NAME)
public OrderService orderService1() {
return new OrderService();
}
或者這樣:
<bean id="userService" class="org.example.spring.bean.UserService" autowire="byType"/>
- 步驟二:處理@Autowired、@Value、@Resource等【自動注入】的屬性填充(注意,之前是尋找注入點,這里才是真正賦值的地方)。這個是本節(jié)課的核心內(nèi)容,后面給大家細(xì)講。
- 步驟三:處理BeanDefinition里面的propertyValues。比如:我們在操作beanDefinition的時候會修改;或者,在第一步處理@Bean的autowire屬性的時候,實際上也是把結(jié)果跟舊有BeanDefinition的propertyValues合并,最后在這里處理注入操作。這個其實也沒啥好講的
下面著重講步驟二【自動注入注解】的屬性填充
6.2 InstantiationAwareBeanPostProcessor#postProcessProperties:處理屬性
我們在前面的【概念回顧】講過,這里用到的,其實還是AutowiredAnnotationBeanPostProcessor
跟CommonAnnotationBeanPostProcessor
,這里就簡單的拿AutowiredAnnotationBeanPostProcessor
舉例吧。
方法調(diào)用鏈:由6.1中的populateBean()調(diào)用進(jìn)來
全路徑:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties
方法注釋:在工廠將給定的屬性值應(yīng)用到給定的bean之前,對它們進(jìn)行后處理,不需要任何屬性描述符。
對應(yīng)流程圖:
源碼如下:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
方法解讀:這里面就干了兩件事,其中第一件事就是【尋找注入點】的入口。我們在前面也介紹過了,并且也說過,【尋找注入點】會在兩個地方被調(diào)用,這里就是說的第二個地方。但是這里,通常是直接拿到了緩存里面的東西的,重新【尋找注入點】的情況不多,這些就屬于【細(xì)枝末節(jié)】了,畢竟看不看對我們掌握整體脈絡(luò)影響不大。
所以,這里最主要的還是看這個metadata.inject()
方法,一看就知道是注入的意思
6.3 InjectionMetadata#inject:根據(jù)注入點注入
方法調(diào)用鏈:由6.2中的postProcessProperties()調(diào)用過來
全路徑:org.springframework.beans.factory.annotationInjectionMetadata#inject
方法注釋:注入目標(biāo)類的屬性
源碼如下:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
方法解讀:方法挺簡單的,這個this.injectedElements
就是我們在【尋找注入點】階段緩存起來的注入點信息。那么大家還記得這里的注入點信息有哪些嗎?哈,就是字段類、方法類封裝出來的對象嘛。這里就是遍歷所有,無論是方法類還是字段類的注入點了,然后依次調(diào)用對方的注入方法。
說到這里,Spring為了維護(hù)【單一職責(zé)】性,對于不同的注入對象,設(shè)計了兩個類。分別是:
- AutowiredFieldElement:表示有關(guān)帶注解【字段】的注入信息
- AutowiredMethodElement:表示有關(guān)帶注解【方法】的注入信息
他們兩個是AutowiredAnnotationBeanPostProcessor
定義的內(nèi)部類
老樣子,這兩個都差不多,我們拿AutowiredFieldElement
的element.inject()
舉例吧
6.4 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject:字段類屬性注入【入口】
方法調(diào)用鏈:由6.3的inject()調(diào)用過來
全路徑:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
方法注釋:就是簡單的,執(zhí)行元素注入邏輯
源碼如下:
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
方法解讀:很顯然,我們第一次調(diào)用,理論上是沒有緩存的,所以我們直接看else
的邏輯
6.5 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue:解決字段屬性注入【入口】
方法調(diào)用鏈:由6.4的inject()調(diào)用過來
全路徑:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
源碼如下:
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
// 步驟一:屬性注入準(zhǔn)備工作
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
try {
// 步驟二:屬性注入
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
// 步驟三:設(shè)置bean依賴信息
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
}
}
方法解讀:這里整體來說也是可以拆分成三個步驟來看的。
第一步就是做屬性注入前的準(zhǔn)備啦,比如之前設(shè)置的required
屬性,還有什么類型轉(zhuǎn)換器,確保bean工廠存在等等;
第二步是核心,下面講,真正處理屬性注入的地方;
第三步是設(shè)置bean依賴信息。這是啥?簡單說就是為了方便后期維護(hù),新增了兩個map來記錄bean之間的相互依賴關(guān)系。這兩個map分別為:
- dependentBeanMap:記錄bean依賴了哪些bean。以beanName記錄
- dependenciesForBeanMap:記錄bean被哪些bean依賴了。也是以beanName記錄
6.6 DefaultListableBeanFactory#resolveDependency:解決屬性注入【入口】
方法調(diào)用鏈:由6.5的resolveFieldValue()而來
全路徑:org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
方法注釋:根據(jù)此工廠中定義的bean解析指定的依賴項。
對應(yīng)流程圖:
源碼如下:
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
方法解讀:這里開始就很多判斷了,判斷這個屬性要怎么注入,要不要注入。前面這三個if-elseif-elseif
說實在不看,顯然我們在使用Spring的時候,基本上也不會用到這幾個類型。感興趣的朋友自己去看吧。我們直接看最后的else
。
這里有一個細(xì)節(jié),如果判斷到需要注入的地方,有@Lazy
,那就直接返回一個【代理對象】,并且直接返回了(這里的寫法是判斷result==null
來確定是不是有@Lazy
)。不知道有沒有人想過,為什么要用代理對象?啊,大家還記得前面文章提到的【代理范式】嗎?
// 代理對象
public class ProxyModel extends ProxyTarget {
private ProxyTarget proxyTarget;
public void setProxyTarget(ProxyTarget proxyTarget) {
this.proxyTarget = proxyTarget;
}
@Override
public void run() {
System.out.println("我代理對象可以在這里做加強---1");
super.run();
System.out.println("我代理對象也可以在這里做加強---2");
}
}
就上面這個。然后我們在回憶一下懶加載的特點,不就是使用的時候再注入嘛。所以,在代理模式下,在每個懶加載屬性的調(diào)用方法里面做個proxyTarge==null
的判斷不就得了嘛。這就是為什么返回代理對象的原因
6.7 DefaultListableBeanFactory#doResolveDependency:解決屬性注入,真正干活的地方
方法調(diào)用鏈:由6.6的resolveDependency()而來
全路徑:org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法注釋:解決屬性注入,真正干活的地方文章來源:http://www.zghlxwxcb.cn/news/detail-659872.html
對應(yīng)流程圖:
到了這里源碼就有點長了,就不截圖看了。說到方法長,還是想吐槽因為跟之前的代碼風(fēng)格不一樣,這個作者明顯懶一點。文章來源地址http://www.zghlxwxcb.cn/news/detail-659872.html
學(xué)習(xí)總結(jié)
到了這里,關(guān)于【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!