Spring 源碼解析——IOC 源碼解析(BeanPostProcessor 系列之 AutowiredAnnotationBeanPostProcessor)(五)

寫文章不易,轉載請標明出處。

同時,如果你喜歡我的文章,請關注我,讓我們一起進步。

一、概述

在前面的一篇博文中我們已經分析了 ApplicationContextAwareProcessor 這個 BeanPostProcessor 實現類,在這篇博文中我們將繼續前行來分析 Spring 當中另一個至關重要的 AutowiredAnnotationBeanPostProcessor,這個 BeanPostProcessor 實現了 Spring 當中最重要的屬性自動注入功能,與其相關聯的就是我們最常見也是最常使用的 @Autowired 註解。

在開始之前還是先絮叨絮叨一些閒話,本來這個 BeanPostProcessor 系列解析博文是想按照上篇博文中的順序來進行的,但是在早上起來的時候突然回想起前段時間的那個 Bean 單例循環依賴解決方案,突然對 @Autowired 註解充滿了興趣,很好奇它的內部是怎麼實現的,因此臨時決定將對於 AutowiredAnnotationBeanPostProcessor 的解析博文往前提一些。

最後在開始之前聲明一下,對於 AutowiredAnnotationBeanPostProcessor 是 Spring 當中特別重要的一個類,它的實現涉及了 Spring 的 DI 核心功能(並且包括部分對於注入方式的選取過程),爲了能夠對 AutowiredAnnotationBeanPostProcessor 進行一個全方位多角度的詳細解析這篇博文的篇幅可能會很長,大概的編寫思路就是先通過官方文檔的閱讀了解 @Autowired 的功能,然後是 AutowiredAnnotationBeanPostProcessor 類的功能,然後是對於 AutowiredAnnotationBeanPostProcessor 這個類源碼的單獨解析,最後纔是去分析它在 Spring 當中的被調用流程,不過我相信經過這篇博文的洗禮,你一定會對 Spring 的自動注入有一個更深刻且更清晰的瞭解,下面就開始正文。

二、功能分析(官方文檔解析)

首先,對於功能的分析,我想強調的一點就是任何拋開官方文檔談功能的分析都是耍流氓,因此本着認真負責並且不做流氓的態度,我們所有的分析都會基於官方文檔,在這裏我們會重點分析官方文檔中對於 @Autowired 註解和 AutowiredAnnotationBeanPostProcessor 類的功能介紹。

2.1 @Autowire 註解

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-autowired-annotation

 @Autowired 是我們經常使用的一個 Spring 註解,主要的功能就是完成 Spring 當中的 Bean 自動注入工作,對於 @Autowired 的使用方法一般有下面幾種:

(1)可以將 @Autowired 註解應用於構造函數,從 Spring Framework 4.3 開始,如果目標 Bean 只定義了一個構造函數,那麼就不再需要在這樣的構造函數上使用 @Autowired 註解。但是,如果有多個構造函數可用,則必須至少註釋一個構造函數,以便告訴容器使用哪個構造函數;

(2)還可以將 @Autowired 註解應用於傳統的 setter 方法

(3)還可以將 @Autowired 註解應用於具有任意名稱和多個參數的方法

(4)還可以將 @Autowired 註解應用於屬性,甚至可以將它與構造函數混合使用,當 @Autowired 註解作用於屬性時,屬性的類型可以爲數組或列表等,且當屬性的類型爲數組(數組元素爲某個指定類型時)或類型集合(泛型語法 <>)時,可以從 ApplicationContext 中獲取指定類型的所有 Bean,例如當 @Autowired 所作用的屬性類型爲 Entity[] 或類似於 Set<Entity> 的泛型集合時,可以獲取到容器中所有類型爲 Entity 的 Bean(@Autowired 默認爲 autowired by type)。

但是需要注意的是上述數組或集合中 Bean 的循序是按照其 BeanDefinition 在容器中的註冊順序進行排列的,如果我們想要指定它們的順序,需要使用 @Order(會影響注入點的優先級,但是不會影響單例啓動順序)或 @Priority 註解。還有一種情況即當屬性類型爲 Map 時,只要當 Map 的鍵爲 String 類型時,依然可以進行正常的注入,比如假設當 @Autowire 所作用的屬性類型爲 Map<String,Entity>,此時 Map 的鍵爲 BeanName,值爲 Entity 類型的 Bean 。

除了上面所述的 @Autowired 的幾種應用點,還需要注意的是 @Autowired 中的 required 屬性(類似於 @Required 註解),這個屬性意味着當前 Bean 注入是否必須成功,當這個 required 爲 true 意味着當 Spring 查找不到合適的 Bean 時就要拋出異常,而當 required 爲 false 時以爲着當前注入非必須,即如果查找不到合適的 Bean 來注入就直接跳過此次注入,不會拋出異常(這種情況下如果非必需方法的依賴項(或者多個參數的依賴項之一)不可用,則根本不會調用該方法)。

最後,我們還可以將 @Autowired 用於衆所周知的可解析依賴關係的接口:BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher 和 MessageSource。這些接口及其擴展接口(如ConfigurableApplicationContext 或 ResourcePatternResolver)將自動解析,無需特殊設置。

2.2 AutowiredAnnotationBeanPostProcessor

BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary config methods. Such members to be injected are detected through a Java 5 annotation: by default, Spring's @Autowired and @Value annotations.

Also supports JSR-330's @Inject annotation, if available, as a direct alternative to Spring's own @Autowired.

首先  AutowiredAnnotationBeanPostProcessor 是 BeanPostProcessor 的一個實現類,它的主要功能是對帶註解的方法、set 方法和任意配置方法進行自動注入,而這些要注入的成員是通過 Java 5 註解被檢測到的,默認情況下這些註解包括 Spring 的 @Autowired 和 @Value 註解。如果可以的話,還支持 JSR-330 的 @Inject 註解,它們的功能是基本相同的,可以使用 @Inject 直接替代 Spring 自己的 @Autowired,並且不管是 @Inject 還是 @Autowired 註解都是基於 AutowiredAnnotationBeanPostProcessor 實現的。

與之類似的還有 @Resource 註解,它是 JSR-250 中的實現,它與上面的兩個類似但不相同,主要是因爲它的底層是依賴另一個 CommonAnnotationBeanPostProcessor 來實現的(當然這個 BeanPostProcessor 也在我們將要分析的列表中),同時 @Resource 的默認實現是 autowired by field name,當其失敗時纔會退化爲 autowired by type,而 @Autowired 和 @Inject 的默認實現都是 autowired by type

Only one constructor (at max) of any given bean class may carry this annotation with the 'required' parameter set to true, indicating the constructor to autowire when used as a Spring bean. If multiple non-required constructors carry the annotation, they will be considered as candidates for autowiring. The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a default constructor (if present) will be used. An annotated constructor does not have to be public.

Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public.

任何給定 Bean 中只有一個構造函數(最多一個)時可以攜帶這個註釋,並應將 required 參數設置爲 true,這表明在將構造函數用作 Spring Bean 時,它將自動裝配。如果多個非必需構造函數攜帶註釋,那麼它們將被視爲自動裝配的候選構造函數。Spring 將會選擇容器中匹配 Bean 且滿足最多依賴關係的構造函數。如果沒有一個候選項滿足,那麼將使用缺省構造函數(如果存在),且帶註解的構造函數不必是 public

屬性在創建 Bean 之後立即注入,然後纔會調用配置方法,因此這樣的配置屬性不必是 public 的

Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Config methods do not have to be public.

 配置方法可以有任意的名稱和任意數量的參數,這些參數中的每一個都將由 Spring 容器中匹配的 Bean 自動生成。Bean 屬性設置方法實際上只是這種通用配置方法的一個特例,且配置方法不必是 public 的

Note: A default AutowiredAnnotationBeanPostProcessor will be registered by the "context:annotation-config" and "context:component-scan" XML tags. Remove or turn off the default annotation configuration there if you intend to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.

Annotation injection will be performed before XML injection; thus the latter configuration will override the former for properties wired through both approaches.

注意:默認的 AutowiredAnnotationBeanPostProcessor 將由 context:annotation-config 和 context:component-scan XML 標記註冊,如果打算指定自定義 AutowiredAnnotationBeanPostProcessor 的 BeanDefinition,請刪除或關閉其中的默認註釋配置。 

註釋注入將在 xml 注入之前執行,因此,對於通過兩種方法注入的屬性,後一種配置將覆蓋前一種配置

In addition to regular injection points as discussed above, this post-processor also handles Spring's @Lookup annotation which identifies lookup methods to be replaced by the container at runtime. This is essentially a type-safe version of getBean(Class, args) and getBean(String, args). 

最後,除了上面討論的常規注入點之外,這個後置處理器還會處理 Spring 的 @Lookup 註解,該註解標識在運行時需要被容器替換的查找方法,這本質上是 getBean(Class,args)和 getBean(String,args)的類型安全版本。這裏可以簡單介紹一下 @Lookup 註解,它的作用就是爲了解決當相互依賴的兩個 Bean 作用範圍或者說生命週期不同時的注入問題(主要是針對當在一個單例 Bean 中注入原型 Bean 時,單例 Bean 沒有辦法總獲取到最新的原型 Bean 實例的情況)。

三、源碼解析

對於 AutowiredAnnotationBeanPostProcessor 的代碼調用主要集中在實例化和初始化 Bean 的過程中,因爲在之前的博文中已經多次分析過 Bean 的實例化和初始化流程和相關的代碼調用了,因此在這篇博文中就不再贅述,直接從 doCreateBean 方法開始進行梳理(對於這個方法的調用鏈可以查閱前面的博文)。首先,我們需要對 Spring 當中對 AutowiredAnnotationBeanPostProcessor 的方法調用有一個大概印象。

通過我自己對源碼的梳理髮現 AutowiredAnnotationBeanPostProcessor 的調用邏輯主要集中在 doCreateBean 方法中(還有一部分集中在 Spring MVC 中,這裏就先不分析了),並且主要分爲三個部分,第一個部分是在實例化 Bean 的時候在 createBeanInstance 方法中會調用 AutowiredAnnotationBeanPostProcessor 中的方法來獲取需要自動注入的構造方法,第二部分是在調用所有 MergedBeanDefinitionPostProcessor 時會調用到 AutowiredAnnotationBeanPostProcessor 的方法來完成對所有需要自動注入的屬性和方法的解析和緩存,最後一部分就是在 populatedBean 方法中調用到 AutowiredAnnotationBeanPostProcessor 中的方法來完成需要自動注入屬性的注入工作。

最後,爲了便於大家理解,對於這上述三部分調用點的代碼我已經貼在了下方,下面開始正式的源碼解析。

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
                ...
		if (instanceWrapper == null) {
		        // 1.處理自動注入構造方法
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		...
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
                                        // 2.掃描註解並緩存注入信息
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
			}
		}
                ...
		Object exposedObject = bean;
		try {
                        // 3.完成屬性注入
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
                ...
		return exposedObject;
	}

3.0 示例代碼 

@Component
public class BeanA {

	@Autowired
	private BeanB beanB; // 屬性自動注入
	private BeanC beanC; // 構造方法自動注入
	private BeanD beanD; // 方法自動注入

	@Autowired
	public BeanA (BeanC beanC){
		this.beanC = beanC;
	}

	@Autowired
	public void setBeanD (BeanD beanD){
		this.beanD = beanD;
	}
}

3.1 處理自動注入的構造方法

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	...
	// 自動裝配的候選構造函數
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// 獲取默認構造的首選構造函數
	ctors = mbd.getPreferredConstructors();
	if (ctors != null) {
		return autowireConstructor(beanName, mbd, ctors, null);
	}

	// 不需要特殊處理則只需使用無參構造函數。
	return instantiateBean(beanName, mbd);
}

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName) throws BeansException {

	if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                                // 當 bp 爲 AutowiredAnnotationBeanPostProcessor 時首先進行強轉
				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                                // 然後調用其 determineCandidateConstructors 方法獲取候選構造方法
				Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
				if (ctors != null) {
					return ctors;
				}
			}
		}
	}
	return null;
}

 第一部分主要是 AutowiredAnnotationBeanPostProcessor 對於構造方法自動注入的處理,這部分代碼的入口就是 createBeanInstance 當中的 determineConstructorsFromBeanPostProcessors 方法,這個方法會通過不同的 BeanPostProcessor 來獲取 Bean 不同種類的構造方法。而在這個方法中主要的邏輯就是首先獲取到所有的 BeanPostProcessor,然後依次來判斷處理,當獲取到的 bp 爲我們研究的 AutowiredAnnotationBeanPostProcessor 時,會先對其進行類型強轉,然後調用它的 determineCandidateConstructors 方法來獲取可選的構造方法(這裏提示一下,determineCandidateConstructors 的代碼邏輯非常非常非常的複雜)。

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException {

	// 查找帶 @Lookup 註解的方法首先判斷 lookupMethodsChecked 集合中是否存在緩存
	if (!this.lookupMethodsChecked.contains(beanName)) {
		try {
                        // 使用反射工具類反射獲取類中的方法
			ReflectionUtils.doWithMethods(beanClass, method -> {
                                // 獲取 @Lookup 註解信息
				Lookup lookup = method.getAnnotation(Lookup.class);
                                // 如果 @Lookup 註解信息不爲空
				if (lookup != null) {
					Assert.state(this.beanFactory != null, "No BeanFactory available");
                                        // 獲取 @Lookup 註解所標記的方法的重寫方法
					LookupOverride override = new LookupOverride(method, lookup.value());
					try {
                                                // 獲取當前 Bean 的 BeanDefinition
						RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
                                                // 將重寫後的方法添加進去
						mbd.getMethodOverrides().addOverride(override);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(beanName,
								"Cannot apply @Lookup to beans without corresponding bean definition");
					}
				}
			});
		}
		catch (IllegalStateException ex) {
			throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
		}
                // 將該 BeanName 添加到已檢 Lookup 方法集合中(不管其包不包含 @Lookup 註解)
		this.lookupMethodsChecked.add(beanName);
	}

	// 首先嚐試從候選構造方法緩存中獲取當前類的候選構造方法
	Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
        // 如果緩存中不存在當前類的候選構造方法緩存
	if (candidateConstructors == null) {
		// 使用鎖來同步下列操作
		synchronized (this.candidateConstructorsCache) {
			candidateConstructors = this.candidateConstructorsCache.get(beanClass);
                        // 雙重判斷防止多線程重複執行
			if (candidateConstructors == null) {
				Constructor<?>[] rawCandidates;
				try {
                                        // 獲取所有聲明的構造方法
					rawCandidates = beanClass.getDeclaredConstructors();
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName,
								"Resolution of declared constructors on bean Class [" + beanClass.getName() +
								"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
				}
				List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                                // 必須注入構造方法集合
				Constructor<?> requiredConstructor = null;
                                // 默認構造方法集合
				Constructor<?> defaultConstructor = null;
                                // 主構造方法(Kotlin 語言特性),如果非 Kotlin 則方法直接返回 null
				Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
				int nonSyntheticConstructors = 0;
                                // 遍歷所有聲明的原生構造方法
				for (Constructor<?> candidate : rawCandidates) {
                                        // 判斷是否存在內部類訪問(isSynthetic 這個是個很冷門的知識點)
					if (!candidate.isSynthetic()) {
						nonSyntheticConstructors++;
					}
                                        // 對於一般的 Java 類 primaryConstructor 都爲 null
					else if (primaryConstructor != null) {
						continue;
					}
                                        // 獲取自動注入註解信息
					AnnotationAttributes ann = findAutowiredAnnotation(candidate);
					if (ann == null) {
                                                // 獲取用戶類
						Class<?> userClass = ClassUtils.getUserClass(beanClass);
                                                // 如果用戶類不等於給定類說明使用了 CGLIB 動態代理(此類爲生成的代理類)
						if (userClass != beanClass) {
							try {
                                                                // 獲取給定類的父類構造方法
								Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                                                // 獲取父類的自動注入註解信息
								ann = findAutowiredAnnotation(superCtor);
							}
							catch (NoSuchMethodException ex) {
								// Simply proceed, no equivalent superclass constructor found...
							}
						}
					}
					if (ann != null) {
                                                // 如果必須自動注入的構造方法不爲空直接拋異常
						if (requiredConstructor != null) {
							throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
						}
                                                // 獲取註解中 required 的屬性值
						boolean required = determineRequiredStatus(ann);
                                                // 如果必須自動注入
						if (required) {
                                                        // 此時 candidates 不爲空則拋異常表示已經存在必須自動注入的構造方法了
							if (!candidates.isEmpty()) {
								throw new BeanCreationException(beanName,
											"Invalid autowire-marked constructors: " + candidates +
											". Found constructor with 'required' Autowired annotation: " +
											candidate);
							}
                                                        // 將當前構造函數設置爲必須自動注入構造函數
							requiredConstructor = candidate;
						}
                                                // 將當前構造方法添加到候 candidates 集合中
						candidates.add(candidate);
					}
                                        // 如果構造方法爲無參構造方法則設置爲默認構造方法
					else if (candidate.getParameterCount() == 0) {
						defaultConstructor = candidate;
					}
				}
                                // —————————————————— 到這裏 for 循環結束 ——————————————————
                                // 如果可選構造函數集合 candidates 不爲空
				if (!candidates.isEmpty()) {
                                        // 且當前不存在必須自動注入的構造函數
					if (requiredConstructor == null) {
					        // 如果存在默認構造函數則將默認構造函數作爲備選添加到可選構造函數列表中
						if (defaultConstructor != null) {
							candidates.add(defaultConstructor);
						}
                                                // 如果存在一個可選構造函數但它不是默認構造函數則記錄日誌
						else if (candidates.size() == 1 && logger.isInfoEnabled()) {
								logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
										"': single autowire-marked constructor flagged as optional - " +
										"this constructor is effectively required since there is no " +
										"default constructor to fall back to: " + candidates.get(0));
						}
					}
					candidateConstructors = candidates.toArray(new Constructor<?>[0]);
				}
                                // 如果原生的構造方法只有一個並且爲有參方法則將其添加到可選集合中
				else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
					candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
				}
                                // 如果原生構造方法存在兩個,且存在主構造方法,也存在默認構造方法
                                // 並且主構造方法不等於默認構造方法則將兩個構造方法同時添加到可選集合中
				else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
						defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
					candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
				}
                                // 如果存在一個構造方法存在訪問內部類並且當前存在主類則將主類添加到集合中
				else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
						candidateConstructors = new Constructor<?>[] {primaryConstructor};
				}
				else {
                                // 如果全不匹配則直接創建空集合
					candidateConstructors = new Constructor<?>[0];
				}
                                // 放入緩存集合中
				this.candidateConstructorsCache.put(beanClass, candidateConstructors);
			}
		}
	}
        // 如果獲取到了構造方法集合則返回構造方法集合,否則返回 null
	return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

這個 determineCandidateConstructors 方法是 AutowiredAnnotationBeanPostProcessor 的一個核心方法,主要的作用就是獲取可選的構造方法,而這個方法的代碼非常非常的多,邏輯也是非常非常的複雜,所以可能需要耐下心來一點點的分析,這裏我們就從頭來梳理一下這個方法。

(1)首先第一部分的邏輯是對於 @Lookup 註解的處理(這點在方法的註解上面也提到過),具體的處理邏輯就是先驗證已經檢驗過 @Lookup 註解的方法集合(lookupMethodsChecked)中是否包含當前方法,如果不包含則通過反射工具的 doWithMethods 方法來反射獲取當前類的所有方法,然後對每一個方法調用第二參數的那個 Lambda 表達式進行處理;

(2)表達式中的邏輯即首先獲取類中關於 @Lookup 註解的信息(當不包含 @Lookup 註解時爲空),如果成功獲取到註解信息則證明存在 @Lookup 註解,然後創建一個 LookupOverride 重寫方法對象(就是將原 Class 信息和 Method 信息包裝爲一個新的重寫方法對象)對原方法進行封裝,之後再獲取當前 Bean 所對應的 BeanDefinition 並將剛剛創建的 LookupOverride 重寫方法對象添加到 BeanDefinition 中(因爲 BeanDefinition 記錄着一個 Bean 的相關信息,修改了 BeanDefinition 就意味着修改了將要實例化的 Bean,在這裏具體就是爲將要實例化的 Bean 添加了一個重寫方法),最終處理完畢後將該 BeanName 添加到已檢查集合中(lookupMethodsChecked);

(3)接下來進入到對可選構造方法的處理邏輯,首先是嘗試從緩存池(candidateConstructorsCache)中獲取當前 Bean 所對應的可選構造方法信息,如果獲取成功則直接返回;

(4)如果未獲取到,則進入到處理邏輯中,首先是獲取類中已經聲明的所有構造方法,然後依次對它們進行處理;

(5)對於構造方法的處理首先是判斷 isSynthetic,這個判斷的話是關於內部類的一個判斷,比較冷門,在這裏的作用也不是特別大,所以就不詳細分析,感興趣的話可以自己去搜索一下,進行完這個判斷後又會去判斷它是否是一個主類(這個概念是屬於 kotlin 裏面的,對於 Java 的話上面的獲取方法一般都是返回 null),這個判斷一般情況下都不會進,所以也不用重點考慮;

(6)接下來或通過 findAutowiredAnnotation 方法(這個方法下面會詳細分析)去獲取當前類的 @Autowired 、@Value 和 @Inject 註解信息(因爲這裏這三種註解的功能是相同的,因此這三種註解主要查找到一個就可以返回);

(7)如果最後沒有獲取到註解信息,那麼就進入到第一個邏輯語句塊中,先通過工具類的 getUserClass 方法(該方法返回給定類的用戶定義類:通常只是給定類,但對於CGLIB生成的子類,則返回原始類)來獲取當前類的用戶類,然後判斷當前的給定類和用戶類是否相同,如果不相同則證明當前的類爲 CGLIB 代理類(子類),所以去獲取它父類中聲明的構造方法,並通過 findAutowiredAnnotation 方法再嘗試去獲取其父類中聲明的構造方法的註解信息(@Autowired 、@Value 和 @Inject);

(8)如果最後獲取到了註解信息,那麼首先判斷當前是否已經存在必須自動注入的構造方法(requiredConstructor 是否爲空),如果存在則直接拋出異常,如果不存在則通過 determineRequiredStatus 方法獲取註解中 required 的屬性值,如果當前 required 屬性值爲 true,表示當前構造方法爲必須自動注入方法,如果此時構造方法集合 candidates 中已經存在了構造方法元素,那麼直接拋異常,如果不存在的話則將當前構造方法設置爲必須自動注入方法(requiredConstructor)並添加到 candidates 集合中。如果當前註解中的 required 屬性值爲 false,那麼直接添加到 candidates 集合中即可。

對於這步邏輯需要我們仔細推敲一下,它的理解需要結合着官方文檔,正如下面的官方文檔中所描述的,對於 @Autowired 應用於構造方法時,如果 required 值爲 true,那麼此時只能有一個帶有 @Autowired 註解的構造方法,多一個都不行(拋異常)。反之,如果 required 值爲 false,那麼可以存在多個具有 @Autowired 註解的構造方法,這時它們都會被當做可選構造方法,Spring 會選擇參數匹配度最高的那個構造方法來執行構造,但是如果沒有找到一個合適的構造方法並且不存在主構造方法和默認構造方法,那麼就會拋異常。

Only one constructor of any given bean class may declare @Autowired with the required attribute set to true, indicating the constructor to autowire when used as a Spring bean. Furthermore, if the required attribute is set to true, only a single constructor may be annotated with @Autowired. If multiple non-required constructors declare the annotation, they will be considered as candidates for autowiring. The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a primary/default constructor (if present) will be used. If a class only declares a single constructor to begin with, it will always be used, even if not annotated. An annotated constructor does not have to be public.

(9)如果當前方法爲無參方法則將其設置爲默認構造方法;

(10)當循環處理過所有的構造方法之後,如果當前構造方法集合爲空,並且不存在必須自動注入的構造方法,並且存在默認構造方法,那麼就將默認構造方法添加到可選構造方法集合中;

(11) 如果原生的構造方法只有一個並且爲有參方法則將其添加到可選構造方法集合中;

(12)如果原生構造方法存在兩個,且存在主構造方法,也存在默認構造方法並且主構造方法不等於默認構造方法則將兩個構造方法同時添加到可選構造方法集合中;

(13)如果存在一個構造方法存在訪問內部類並且當前存在主類則將主類添加到可選構造方法集合中;

(14)如果全不匹配則直接創建空集合;

(15)最後以類名爲鍵將剛剛處理好的可選構造方法集合 candidateConstructors 中的元素存儲到 candidateConstructorsCache 緩存池中,並當緩存池不爲空時將其返回,否則返回 null ,至此這個方法分析完畢;

3.2 掃描註解並緩存注入信息

在前面我們已經分析了對於 AutowiredAnnotationBeanPostProcessor 的第一次調用,其主要完成了掃描並處理自動注入的構造方法,當我們完成了自動注入構造方法的處理後會再次返回到 doCreateBean 方法中,在這個方法中會通過調用 applyMergedBeanDefinitionPostProcessors 方法來完成掃描和緩存需要自動注入的屬性和方法的工作。

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof MergedBeanDefinitionPostProcessor) {
			MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
			bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}
}

 對於 applyMergedBeanDefinitionPostProcessors 的代碼邏輯比較簡單,即首先獲取所有的 BeanPostProcessor(這裏泛指 BeanPostProcessor 接口實現類的對象),然後再判斷其是否爲 MergedBeanDefinitionPostProcessor 接口的實現類對象,如果是的話就將其強轉類型後調用它的 postProcessMergedBeanDefinition 方法,從這裏開始就再次進入到了 AutowiredAnnotationBeanPostProcessor 的代碼中。

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 獲取自動注入的元數據
	InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        // 檢查配置成員
	metadata.checkConfigMembers(beanDefinition);
}

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// 返回類名作爲緩存鍵,以便與自定義調用程序向後兼容
	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);
				}
                                // 調用 buildAutowiringMetadata 來構建自動注入元數據
				metadata = buildAutowiringMetadata(clazz);
                                // 將新構建的自動注入元數據放入緩存中
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
        //返回獲取到的注入元數據
	return metadata;
}

public static boolean needsRefresh(@Nullable InjectionMetadata metadata, Class<?> clazz) {    
        // 如果注入元數據爲空或者注入元數據的目標類不是當前類則返回需要更新(true)
	return (metadata == null || metadata.targetClass != clazz);
}

 postProcessMergedBeanDefinition 進行了兩個方法的調用,這裏相對來說比較重要的第一個 findAutowiringMetadata 方法的調用,postProcessMergedBeanDefinition 通過這個方法調用完成了自動注入元數據的獲取工作,而 findAutowiringMetadata 具體的代碼邏輯也比較簡單。

(1)獲取類名作爲元數據緩存集合的鍵,然後首先通過 get 方法來從緩存集合中獲取當前類所對應的元數據,這步的獲取以及下一步的檢查都是爲了儘可能以最小的限度來使用鎖,因爲如果當前類所對應的元數據不存在,那麼接下來的一系列創建添加操作會鎖住資源;

(2)當從併發集合中獲取到當前類所對應的元數據後,調用 needsRefresh 進行判斷,判斷的兩個條件分別是剛剛獲取到的元數據是否爲空,如果不爲空那麼該元數據所對應的目標類是否爲當前類,也就是如果剛剛從集合中沒有獲取到元數據,或者獲取到的元數據出現錯誤,那麼我們都需要進行更新;

(3)上面判斷需要更新後即開始鎖住資源,然後會再進行一次相同的判斷,這部分的原理主要是類似於雙重檢測單例,即這樣實現的目的還是爲了保證線程的安全,因爲當兩個線程同時執行到第一個 needsRefresh 且同時返回 true 後都會進入到 if 語句塊中,之後一個線程 A 會先拿到鎖,另一個線程 B 被阻塞,然後線程 A 拿到鎖之後開始進行創建和添加操作,當其完成添加後釋放鎖,這時線程 B 進入到同步語句塊中,如果此時沒有第二重的判斷,會導致線程 B 再次執行無意義的相同操作。

還有一個問題就是,通過定義我們可以發現 injectionMetadataCache 本身就是一個併發安全的集合(ConcurrentHashMap),那對於它的添加操作本身就是線程安全的,爲什麼還需要使用 Synchronize 鎖來進行同步呢?這裏我認爲主要是因爲雖然對於集合的操作時線程安全的,但是這一系列的操作是非原子的,這一點主要表現在它會調用 buildAutowiringMetadata 方法來創建元數據。因此爲了保證創建元數據併成功添加元數據這一系列的操作成功,所以需要進行同步來保證原子性;

(4)當第二重判斷決定需要刷新時,會首先判斷剛剛獲取到的元數據是否爲空,如果不爲空就證明它所對應的目標類出現了錯誤(needsRefresh 第二個判斷條件),因此需要將它清除;

(5)然後調用 buildAutowiringMetadata 創建元數據,將其添加到 injectionMetadataCache 緩存池中,最後將元數據返回即可;

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
	List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
	Class<?> targetClass = clazz;

	do {
		final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        
                // 使用反射工具類獲取屬性並調用 Lambda 表達式
		ReflectionUtils.doWithLocalFields(targetClass, field -> {
                    // 解析獲取 @Autowired、@Value 和 @Inject 註解信息
			AnnotationAttributes 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;
				}
                                // 獲取註解中的 required 屬性(是否必須自動注入)
				boolean required = determineRequiredStatus(ann);
                                // 使用屬性信息和 required 信息創建 AutowiredFieldElement 對象
                                // 並將其添加到 currElements 集合中
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});

                // 使用反射工具類獲取方法並調用 Lambda 表達式
		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                        // 解析獲取方法獲取橋接方法
			Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                        // 如果橋接方法不可見則直接返回
			if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
				return;
			}
                        // 解析獲取 @Autowired、@Value 和 @Inject 註解信息
			AnnotationAttributes 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);
					}
				}
                                // 獲取註解中的 required 屬性(是否必須自動注入)
				boolean required = determineRequiredStatus(ann);
                                // 爲方法獲取入參
				PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                                // 使用方法信息、required 信息創建以及入參信息創建 AutowiredFieldElement 對象並將其添加到 currElements 集合中
				currElements.add(new AutowiredMethodElement(method, required, pd));
			}
		});

		elements.addAll(0, currElements);
                // 獲取父類
		targetClass = targetClass.getSuperclass();
	}
        // 如果存在父類且不爲 Object 基類則循環進行處理
	while (targetClass != null && targetClass != Object.class);
    
        // 將獲取到的需要自動注入的屬性和方法連同類信息封裝到 InjectionMetadata 對象中返回
	return new InjectionMetadata(clazz, elements);
}

通過上面對 findAutowiringMetadata 方法的分析我們知道在 findAutowiringMetadata 方法中首先會嘗試從緩存中獲取元數據信息,當其獲取失敗時就會調用 buildAutowiringMetadata 方法來創建元數據,而在 buildAutowiringMetadata 方法中對於元數據的構建主要包括兩個部分,一個是對於自動注入屬性的處理,另一部分是對於自動注入方法的處理,因此我們接下來就來分析一下其代碼的邏輯。

(1)首先會調用反射工具類的 doWithLocalFields 方法(方法具體實現在下面)來反射獲取類中的屬性信息,然後對所有的屬性依次調用 FieldCallback 的 doWith 方法(也就是我們在 buildAutowiringMetadata 方法中傳入的 Lambda 表達式);

(2)然後會對單個屬性調用 Lambda 表達式中的代碼邏輯,首先通過 findAutowiredAnnotation 來獲取到當前屬性註解中的關於 @Autowired 、@Value 和 @Inject 信息;

(3)當剛剛獲取到的屬性的註解信息不爲空時,進入下面的邏輯後先判斷當前屬性是否爲靜態屬性,如果爲靜態屬性在打印 log 日誌後直接返回;

(4)之後在通過 determineRequiredStatus 方法(方法具體實現在下面)來解析註解中 required 屬性所對應的值(主要是用於判斷當前屬性是否必須自動注入);

(5)最後將屬性信息和其對應的 required 屬性值包裝爲 AutowiredFieldElement 對象後添加到單輪循環的臨時集合 currElements 中,然後進入到自動注入方法處理的代碼邏輯中;

(6)對於自動注入方法的處理流程類似於屬性處理,首先調用反射工具類的  doWithLocalMethods 方法(方法具體實現在下面)來反射獲取當前類的方法信息,並對所有獲取到的方法調用 MethodCallback 的 doWith 方法來進行處理;

(7)因爲傳入的 MethodCallback 爲一個 Lambda 表達式,因此執行表達式中的代碼邏輯,首先先通過 findBridgedMethod 方法來獲取橋接方法(橋接方法是 JDK 1.5 引入泛型後,爲了使 Java 的泛型方法生成的字節碼和 JDK 1.5 前的字節碼相兼容,由編譯器自動生成的方法),這裏一般返回的就是原方法;

(8)然後判斷橋接方法是否可見(這裏的可見性是指比較橋接方法和橋接方法的函數簽名,如果方法的參數和返回類型都相同,那麼它就是一個可見的橋接方法),如果不可見則直接返回;

(9)然後通過調用 findAutowiredAnnotation 方法來獲取到當前方法註解中的關於 @Autowired 、@Value 和 @Inject 信息;

(10)如果獲取註解信息失敗,或者不存在相關的註解,或者當前解析的方法和類信息不匹配,那麼就跳過這個方法的處理;

(11)如果滿足前面的判斷,則再判斷當前方法是否爲靜態方法或者無參方法,如果當前方法爲靜態方法即打印日誌後返回;

(12)之後在通過 determineRequiredStatus 方法來解析註解中 required 屬性所對應的值(主要是用於判斷當前方法是否必須自動注入,如果爲必須自動注入則當搜索不到合適的 Bean 來注入時就會拋出異常);

(13)通過 findPropertyForMethod 方法查找合適的 JavaBeans 作爲入參(爲後面的方法自動注入做準備);

(14)最後將方法信息、其對應的 required 屬性值以及搜索到的適合注入的 Bean 參數信息包裝爲 AutowiredMethodElement 對象後添加到單輪循環的臨時集合 currElements 中,然後進入到自動注入方法處理的代碼邏輯中;

(15)將臨時集合 currElements 中的元素全部添加到 elements 集合中,並獲取當前類的父類;

(16)噹噹前類存在父類,且父類不爲 Object 基類時進行循環處理父類;

(17)當前類及父類的屬性和方法全部處理完成後將類信息 和 elements 集合封裝到 InjectionMetadata 對象中返回;

protected boolean determineRequiredStatus(AnnotationAttributes ann) {
        // this.requiredParameterValue == true
	return (!ann.containsKey(this.requiredParameterName) ||
		this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
}

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);
		}
	}
}

public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
	Method[] methods = getDeclaredMethods(clazz);
	for (Method method : methods) {
		try {
			mc.doWith(method);
		}
		catch (IllegalAccessException ex) {
			throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
		}
	}
}

 

private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
        // 判斷當前是否存在註解信息
	if (ao.getAnnotations().length > 0) {  // autowiring annotations have to be local
                // 一次判斷是否存在 @Autowired @Value @Inject 註解,存在即返回
		for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
			AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
			if (attributes != null) {
				return attributes;
			}
		}
	}
	return null;
}

 findAutowiredAnnotation 方法主要作用就是判斷當前屬性或者方法是否包含 @Autowired 、@Value 或者 @Inject 註解,如果存在就直接返回註解信息,因爲這三個註解在作用上是相似的,所以只要發現一個就可以終止循環返回了,如果三個註解都沒有發現則返回 null 。對於 autowiredAnnotationTypes 集合中的信息我也貼在上面了,就是我們剛剛提到的三個註解,這三個元素是在初始化的時候被放入的類似於常量,所以不用過多考慮相關的邏輯。

3.3 完成屬性注入

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	...
	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

	PropertyDescriptor[] filteredPds = null;
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
                                // 當 bp 爲 AutowiredAnnotationBeanPostProcessor 時先將其進行強轉
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                // 調用其 postProcessProperties 方法
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				...
			}
		}
	}
	...
}

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        // 通過 findAutowiringMetadata 方法獲取類所對應的注入元數據
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
                // 調用 InjectionMetadata 方法進行屬性注入
		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;
}

	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			...
		}
		return metadata;
	}

最後一個部分就是對需要自動注入的屬性進行屬性的自動注入操作,這部分的代碼主要集中在 populatedBean 中,在這個方法中會在獲取到 AutowiredAnnotationBeanPostProcessor 之後將其進行類型強轉,然後調用它的 postProcessProperties 方法,而在這個 postProcessProperties 法中又一次的調用了 findAutowiringMetadata 方法來獲取元註解,但是這次與第二次的調用的意義不同。

爲了便於理解我把 findAutowiringMetadata 方法的代碼又貼了過來,因爲我們剛剛在上一步的過程中已經完成了對需要自動注入的屬性和方法的元數據緩存工作,也就是說現在緩存池 injectionMetadataCache 的狀態應該是如圖一圖二爲此時 Bean 實例的狀態,即屬性自動注入方法自動注入都還未進行,而構造方法自動注入已經完成),因此這時我們再通過 get 方法是可以獲取到 Bean 所對應的元數據的,所以我們判斷出當前的元數據不需要刷新,然後直接將獲取到的元數據返回,最後在 postProcessProperties 方法中通過該元數據的 inject 方法完成了屬性的注入(圖三)。

四、內容總結

這篇博文主要是對 @Autowired 註解功能、使用方法的原理,以及 AutowiredAnnotationBeanPostProcessor 類的功能原理和源碼進行了比較詳細的分析(就說這麼多吧,實在太累了,每次分析完一部分源碼感覺就被扒了一層皮)。

從沒有白費的努力,也沒有碰巧的成功。只要認真對待生活,終有一天,你的每一份努力,都將絢爛成花。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章