国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入)

這篇具有很好參考價值的文章主要介紹了【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

閱讀準(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é))

  1. AbstractApplicationContext#refresh:刷新方法,不用在意
  2. AbstractApplicationContext#finishBeanFactoryInitialization:在這里實例化所有剩余的(非lazy-init)單例
  3. DefaultListableBeanFactory#preInstantiateSingletons:在這里實例化所有剩余的(非lazy-init)單例(上面的方法,核心干活的方法就是這里)
  4. DefaultListableBeanFactory#getBean:獲取Bean的方法
  5. AbstractBeanFactory#doGetBean:返回指定bean的一個實例,它可以是共享的,也可以是獨立的
  6. 上面這個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);
	}
  1. AbstractAutowireCapableBeanFactory#createBean:這個類的中心方法:創(chuàng)建一個bean實例,填充bean實例,應(yīng)用后處理器,等等。
  2. AbstractAutowireCapableBeanFactory#doCreateBean:【實例化】及后面聲明周期調(diào)用地方。
  3. 【入口一】AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors:應(yīng)用合并BeanDefinition后置處理器給給定的BeanDefinition。
  4. 【入口二】AbstractAutowireCapableBeanFactory#populateBean:使用來自bean定義的屬性值在給定的BeanWrapper中填充bean實例。

如上面的調(diào)用鏈所示,最后兩個方法,才是我們本次要研究的核心方法。為什么這里會說有兩個入口呢?主要是,本章的【屬性填充/依賴注入】將分為兩個部分來解析?!救肟谝弧繉?yīng)的是【第一部分:尋找注入點】;【入口二】對應(yīng)的是【第二部分:屬性填充及填充后】

閱讀建議

  1. 看源碼,切記糾結(jié)細(xì)枝末節(jié),不然很容易陷進(jìn)去。正常來說,看主要流程就好了
  2. 遇到不懂的,多看看類注釋或者方法注釋。Spring這種優(yōu)秀源碼,注釋真的非常到位
  3. 如果你是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的自動填充屬性時流程是:

  1. 獲取到set方法中的唯一參數(shù)的參數(shù)類型,并且根據(jù)該類型去容器中獲取bean
  2. 如果找到多個,會報錯

使用示例如下:

<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的自動填充屬性時流程是:

  1. 找到所有set方法所對應(yīng)的Xxx部分的名字
  2. 根據(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
}

如上,UserXmlBeanWalletXmlBean類型的屬性出現(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的自動填充屬性時流程是:

  1. 通過構(gòu)造方法中的參數(shù)類型去找bean,如果對應(yīng)的類型只有一個bean,那就是它了;
  2. 如果找到多個會根據(jù)參數(shù)名確定
  3. 如果最后根據(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的自動注入底層其實也就是:

  1. set方法注入
  2. 構(gòu)造方法注入
1.2.2 @Autowired注解的自動注入

@Autowired注解,本質(zhì)上也是byType和byName的結(jié)合。它是先byType,如果找到多個則byName。這個跟xml構(gòu)造方式注入原理如出一轍。就是:

  1. 先根據(jù)類型去找bean,如果對應(yīng)的類型只有一個bean,那就是它了;
  2. 如果找到多個會根據(jù)屬性名確定
  3. 如果最后根據(jù)屬性名都無法確定,則報錯

@Autowired注解可以寫在:

  1. 屬性上:先根據(jù)屬性類型去找Bean,如果找到多個再根據(jù)屬性名確定一個(屬性注入)
  2. 構(gòu)造方法上:先根據(jù)方法參數(shù)類型去找Bean,如果找到多個再根據(jù)參數(shù)名確定一個(構(gòu)造方法注入)
  3. 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后置處理】中的一個。
【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫
上面說的概念多少有點繞。簡單來說,【尋找注入點】就是尋找被@Autowird、@Value、@Inject@Resource注解修飾的屬性、方法等等;然后,【屬性填充】的時候再來處理這些找到的注入點,將他們設(shè)置到對應(yīng)Bean屬性中。

2.2 概念回顧

在這個【實例化】過程中,涉及到了一些Spring底層設(shè)計的概念,我在上一個筆記里面有大概介紹過Spring底層概念的一些講解,不記得的同學(xué)記得回去翻一翻。
主要涉及的概念有:

  • BeanDefinition(設(shè)計圖紙):BeanDefinition表示Bean定義,BeanDefinition中存在很多屬性用來描述一個Bean的特征
  • MergedBeanDefinitionPostProcessor:合并BeanDefinition后置處理器。但這里其實主要說的是AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor。他倆有什么作用呢?前者是處理Spring內(nèi)部定義的@Autowired@Value自動注入注解;后者是處理jdk定義的@Resource注解。主要是用到了這個MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition去完成【尋找注入點】的操作
  • InstantiationAwareBeanPostProcessor:感知實例化的Bean后置處理器。這個也是跟上面一樣,其實主要說的也是AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor。這兩個類也繼承了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)類:AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor。為了方便,我們這里就只舉例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 剩余步驟

剩余步驟,干了三件事,如下:

  1. 設(shè)置@Autowired(required = false)這個屬性
  2. 將得到構(gòu)建點包裝成InjectionMetadata.InjectedElement
  3. 將得到的所有注入點,封裝成InjectionMetadata,接著緩存起來

四、【尋找注入點】邏輯流程圖

【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫
流程描述:

  1. 遍歷當(dāng)前類的所有的屬性字段Field
  2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一個,存在則認(rèn)為該字段是一個注入點
  3. 如果字段是static的,則不進(jìn)行注入
  4. 獲取@Autowired中的required屬性的值
  5. 將字段信息構(gòu)造成一個AutowiredFieldElement對象,作為一個注入點對象添加到currElements集合中。
  6. 遍歷當(dāng)前類的所有方法Method
  7. 判斷當(dāng)前Method是否是橋接方法,如果是找到原方法
  8. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一個,存在則認(rèn)為該方法是一個注入點
  9. 如果方法是static的,則不進(jìn)行注入
  10. 獲取@Autowired中的required屬性的值
  11. 將方法信息構(gòu)造成一個AutowiredMethodElement對象,作為一個注入點對象添加到currElements集合中。
  12. 遍歷完當(dāng)前類的字段和方法后,將遍歷父類的,直到?jīng)]有父類。
  13. 最后將currElements集合封裝成一個InjectionMetadata對象,作為當(dāng)前Bean對于的注入點集合對象,并緩存。

四點五、特別聲明

兄弟們,提前聲明一下,下面的內(nèi)容個人感覺特別復(fù)雜,是我按照Spring源碼閱讀順序以來,目前最復(fù)雜的一部分。不過也由于分了兩個部分,層次感還是有的,所以大家如果是在沒有繼續(xù)看下去的欲望了,剩下的下次再看吧。[/狗頭][/狗頭]
所以,我想著,在后面的講解中,換一種方式來寫寫。

  1. 首先,我會先給出流程圖,并且按照樹形結(jié)構(gòu)的方式寫
  2. 其次,我將按照源碼調(diào)用次序,【自上而下、從左往右】的方式映射到樹形結(jié)構(gòu)上
  3. 最后到了這里,我感覺大家需要打開Spring源碼,一邊看文章,一邊看源碼的方式來閱讀了
  4. 我并不會講解所有的源碼,只會將一些比較陌生、或者關(guān)鍵的源碼點一下

五、【屬性填充】邏輯流程圖

整體源碼邏輯流程圖如下:(畫的我吐血)
【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫

圖片點開來很不清晰,建議大家:右鍵、新建窗口打開。 然后就可以放大觀看了

六、【屬性填充】方法講解

我們在【閱讀建議】中已經(jīng)說過【入口二】是AbstractAutowireCapableBeanFactory#populateBean。在這個方法,我們在上面屬性流程圖畫的第一二層,講的就是這個方法。

6.1 AbstractAutowireCapableBeanFactory#populateBean

全路徑:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
方法解釋:使用來自bean定義的屬性值在給定的BeanWrapper中填充bean實例。

對應(yīng)流程圖:
【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫

源碼如下:(標(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:處理屬性

我們在前面的【概念回顧】講過,這里用到的,其實還是AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor,這里就簡單的拿AutowiredAnnotationBeanPostProcessor舉例吧。

方法調(diào)用鏈:由6.1中的populateBean()調(diào)用進(jìn)來
全路徑:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties
方法注釋:在工廠將給定的屬性值應(yīng)用到給定的bean之前,對它們進(jìn)行后處理,不需要任何屬性描述符。

對應(yīng)流程圖:
【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫

源碼如下:

	@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)部類
老樣子,這兩個都差不多,我們拿AutowiredFieldElementelement.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)流程圖:
【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫

源碼如下:

	@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)。不知道有沒有人想過,為什么要用代理對象?啊,大家還記得前面文章提到的【代理范式】嗎?
【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫

// 代理對象
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
方法注釋:解決屬性注入,真正干活的地方

對應(yīng)流程圖:
【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入),tuling學(xué)院學(xué)習(xí)筆記,spring,java,數(shù)據(jù)庫
到了這里源碼就有點長了,就不截圖看了。說到方法長,還是想吐槽因為跟之前的代碼風(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)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【Spring】Spring之Bean生命周期源碼解析

    什么是bean的生命周期 是指bean在spring中是如何生成,如何銷毀的; spring創(chuàng)建對象的過程,就是IOC(控制反轉(zhuǎn))的過程; JFR Java Flight Record,java飛行記錄,類似于飛機的黑匣子,是JVM內(nèi)置的基于事件的JDK監(jiān)控記錄框架,主要用于問題定位和持續(xù)監(jiān)控; 入口代碼: Spring啟動的時

    2024年02月15日
    瀏覽(23)
  • 【框架源碼】Spring源碼解析之Bean生命周期流程

    【框架源碼】Spring源碼解析之Bean生命周期流程

    觀看本文前,我們先思考一個問題,什么是Spring的bean的生命周期?這也是我們在面試的時候,面試官常問的一個問題。 在沒有Spring之前,我們創(chuàng)建對象的時候,采用new的方式,當(dāng)對象不在被使用的時候,由Java的垃圾回收機制回收。 而 Spring 中的對象是 bean,bean 和普通的 J

    2024年02月09日
    瀏覽(21)
  • 【深入Spring源碼解析:解密Bean的生命周期】

    Spring是Java企業(yè)級應(yīng)用開發(fā)領(lǐng)域的一顆明星,它提供了很多方便開發(fā)人員的工具和思想。在分布式系統(tǒng)中,Spring的分布式遠(yuǎn)程協(xié)作方案,比如REST、Web服務(wù)以及消息傳遞等,也是不可或缺的。 你知道嗎?在我們使用Spring時,容器中存放的所有對象,在Spring啟動的時候就完成了實

    2024年02月05日
    瀏覽(28)
  • Spring的Bean生命周期有哪些階段?

    Spring的Bean生命周期分為四個階段:實例化、屬性賦值、初始化和銷毀。 實例化:Spring容器負(fù)責(zé)創(chuàng)建Bean的實例,可以通過構(gòu)造方法或者無參構(gòu)造方法進(jìn)行實例化。 屬性賦值:Spring容器通過屬性注入的方式為Bean的屬性賦值,可以通過setter方法或者無參構(gòu)造方法進(jìn)行屬性賦值。

    2024年02月09日
    瀏覽(28)
  • 深入理解 Java Bean 的生命周期及各個階段解析

    深入理解 Java Bean 的生命周期及各個階段解析

    Java Bean是Java編程中經(jīng)常使用的重要概念,它是可重用、可移植、可序列化的組件。在Java開發(fā)中,我們常常會遇到Bean對象,但是對于Bean的生命周期和各個階段可能并不完全了解。本文將深入探討Java Bean的生命周期,逐步解析Bean對象從創(chuàng)建到銷毀的各個重要階段。 Java Bean是一

    2024年02月14日
    瀏覽(21)
  • 【Spring專題】Bean的生命周期流程圖

    【Spring專題】Bean的生命周期流程圖

    我向來不主張【通過源碼】理解業(yè)務(wù),因為每個人的能力有限,甚至可能會因為閱讀錯誤導(dǎo)致出現(xiàn)理解上的偏差,所以我決定,還是先幫大家【開天眼】,先整體看看流程圖,好知道,Spring在寫源碼的過程中到底干了啥事情。 對于【一、之前推測的簡單流程圖】大家可以不看

    2024年02月13日
    瀏覽(34)
  • Spring源碼:Bean生命周期(五)

    在上一篇文章中,我們深入探討了 Spring 框架中 Bean 的實例化過程,該過程包括從 Bean 定義中加載當(dāng)前類、尋找所有實現(xiàn)了 InstantiationAwareBeanPostProcessor 接口的類并調(diào)用實例化前的方法、進(jìn)行實例化、調(diào)用 applyMergedBeanDefinitionPostProcessors 方法等多個步驟,最終生成了一個真正的

    2024年02月04日
    瀏覽(21)
  • Spring源碼:Bean生命周期(終章)

    本系列前面講解了Spring的bean定義、bean實例化、bean初始化等生命周期。這些步驟使我們能夠了解bean從創(chuàng)建到準(zhǔn)備好使用所經(jīng)歷的過程。但是,除了這些步驟,bean的銷毀也是非常重要的一步。在本系列的最后,我們將深入探討bean的銷毀過程,包括在什么情況下會發(fā)生銷毀、銷

    2024年02月06日
    瀏覽(35)
  • Spring源碼:Bean生命周期(三)

    在之前的文章中,我們已經(jīng)對 bean 的準(zhǔn)備工作進(jìn)行了講解,包括 bean 定義和 FactoryBean 判斷等。在這個基礎(chǔ)上,我們可以更加深入地理解 getBean 方法的實現(xiàn)邏輯,并在后續(xù)的學(xué)習(xí)中更好地掌握 createBean 方法的實現(xiàn)細(xì)節(jié)。 講解getBean方法之前,我們先來看看他有幾種常見的用法:

    2024年02月02日
    瀏覽(23)
  • Spring源碼:bean的生命周期(一)

    Spring源碼:bean的生命周期(一)

    本節(jié)將正式介紹Spring源碼細(xì)節(jié),將講解Bean生命周期。請注意,雖然我們不希望過于繁瑣地理解Spring源碼,但也不要認(rèn)為Spring源碼很簡單。在本節(jié)中,我們將主要講解Spring 5.3.10版本的源代碼。如果您看到的代碼與我講解的不同,也沒有關(guān)系,因為其中的原理和業(yè)務(wù)邏輯基本相

    2024年02月02日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包