AutowireCapableBeanFactory探密(3)——依賴解析

前情回顧

在前兩篇文章中,多次提及AutowireCapableBeanFactory#resolveDependency方法,原因是該方法很重要,在Spring很多場合都涉及該方法的調用,包括但不限於以下場景:

  1. 解析@Resouce註解的元素(CommonAnnotationBeanPostProcessor#autowireResource)
  2. 解析@Autowired、@Value註解的元素(AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject、AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject)
  3. autowire = byType(AbstractAutowireCapableBeanFactory#autowireByType)
  4. 構造器裝配(ConstructorResolver#resolveAutowiredArgument)

瞭解此方法的底層工作原理,有助於提升對Spring Bean解析的認知能力

案例

本文以一種經典的注入案例進行探討:注入集合對象

// 接口
public interface BarService {}

// 實現類1
@Service
public class BarServiceImplOne implements BarService {}

// 實現類2
@Service
public class BarServiceImplTwo implements BarService {}


@Service
public class FooService {
    // barServices集合有兩個元素,分別是BarServiceImplOne、BarServiceImplTwo
    @Resource
    private List<BarService> barServices;
}

注入集合的姿勢Spring官網就有介紹,開發中也比較常用,現在藉助該方式來探尋其中的一些細節問題,並介紹resolveDependency在其中起了怎樣的作用

源碼分析

源碼基於Spring 5.1.11.RELEASE

resolveDependency翻譯成中文即是解析依賴,其方法簽名如下:

Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
  • descriptor: 依賴描述符,它描述了一個待注入的依賴信息:要麼是構造器參數,要麼是方法參數,要麼是字段,並且提供了非常友好的、一種統一的方式去訪問
  • requestingBeanName: 聲明依賴的Bean。舉例,如果A依賴B,則requestingBeanName表示的是A
  • autowiredBeanNames: 待裝配的Bean名稱列表,即解析出來的bean names。使用上,一般是由外部傳進來一個空的集合,在方法內部進行Bean的解析,如果符合條件,就將該bean name添加到集合內。潛臺詞是,可能會有多個符合條件的Bean,其實也很好理解,如果被依賴的類(接口)有多個實現類,且都被Spring管理,就存在多個符合條件的Bean的可能性
  • typeConverter: 類型轉化器,用於類型轉換

由於使用的是@Resouce註解,故直接定位到CommonAnnotationBeanPostProcessor#autowireResourceAutowireCapableBeanFactory探密(2)——傳統裝配模式與現代註解驅動注入方式一文中也有簡單的介紹

protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
		throws NoSuchBeanDefinitionException {
	// ...(省略)

	if (factory instanceof AutowireCapableBeanFactory) {
		AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
		// 依賴描述符
		DependencyDescriptor descriptor = element.getDependencyDescriptor();
		if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
			// 滿足條件,進入該分支
			// 空集合
			autowiredBeanNames = new LinkedHashSet<>();
			// 進行Bean解析, requestingBeanName: fooService
			resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
			if (resource == null) {
				throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
			}
		}
	// ...(省略)
}

接着調用beanFactory.resolveDependency

// DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
	// 初始化參數解析器
	descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
	// 處理依賴類型爲Option類的case,很顯然,需要JDK1.8以上才支持,一般不會進入此處
	if (Optional.class == descriptor.getDependencyType()) {
		return createOptionalDependency(descriptor, requestingBeanName);
	}
	// 處理類型爲ObjectFactory、ObjectProvider,略過
	else if (ObjectFactory.class == descriptor.getDependencyType() ||
			ObjectProvider.class == descriptor.getDependencyType()) {
		return new DependencyObjectProvider(descriptor, requestingBeanName);
	}
	// 處理類型爲JSR-330的javax.inject.Provider,略過
	else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
		return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
	}
	// 99%的情況進入else的分支
	else {
		// 處理@Lazy 註解的情況,一般特殊需要纔會在字段或方法上標註@Lazy,不是本文重點,略過
		Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
				descriptor, requestingBeanName);
		if (result == null) {
			// 大部分情況會走下面的case,進行真正的解析
			result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
		}
		return result;
	}
}

雖然有很多條件分支存在,但大部分場景都不會用到,因此只需要關注result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);這一行核心代碼即可

有意思的是,一些人認爲Spring考慮周全,兼容各種case,360度無死角,正是Java web領域它獨領風騷的魅力之所在;與此同時,另一些人認爲正是因爲考慮太周全,Spring變的越來越臃腫不堪,代碼閱讀越發困難,需要瘦瘦身,甚至需要一個更輕量級的框架來替代。天下大勢,分久必合,合久必分,蒼天饒過誰?

整體上看一下doResolveDependency方法核心邏輯

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
	try {
		// 只有ShortcutDependencyDescriptor實現了resolveShortcut方法,返回了非空值。目前版本代碼只在AutowiredFieldElement、AutowiredMethodElement類中使用到,也即是說,只有解析@Autowired、@Value註解的元素纔會用到,目的是爲了將解析結果緩存起來,避免重複解析
		Object shortcut = descriptor.resolveShortcut(this);
		if (shortcut != null) {
			return shortcut;
		}
		// 依賴的類型type: java.util.List
		Class<?> type = descriptor.getDependencyType();
		
		// 處理@Value註解,取值註解中的value屬性中的值(原樣,未經過解析的),如果descriptor未被@Value標註,則返回null
		// 注:從此處可知,@Value註解的優先級較高,只要找到了就處理,不再往下走
		Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
		if (value != null) {
			if (value instanceof String) {
				// 處理佔位符如${},做佔位符的替換(不解析SP EL表達式)
				String strVal = resolveEmbeddedValue((String) value);
				BeanDefinition bd = (beanName != null && containsBean(beanName) ?
						getMergedBeanDefinition(beanName) : null);
				// 解析SP EL(如#{})
				value = evaluateBeanDefinitionString(strVal, bd);
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			try {
				// 類型轉換,把解析出來的結果轉成type類型
				return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
			}
			catch (UnsupportedOperationException ex) {
				// A custom TypeConverter which does not support TypeDescriptor resolution...
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}
		}
		// 本文重點,解析"集合類"Bean,如果依賴的類型不是"集合類",則返回null
		// 注:"集合類"是口語描述,目的是方便記憶,實際上,還支持數組類型和Map類型
		
		/**
	 	* 1. array
	 	* 2. Collection及其子類
	 	* 3. Map
	 	*/
		Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
		if (multipleBeans != null) {
			return multipleBeans;
		}

		// 代碼走到此處,說明依賴的是非"集合類",
		// 查找所有類型爲type的實例,存放在matchingBeans <beanName, bean>
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		if (matchingBeans.isEmpty()) {
			if (isRequired(descriptor)) {
				// 如果IoC容器中找不到符合條件的Bean,且依賴項標識爲required,則拋出NoSuchBeanDefinitionException異常
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			return null;
		}

		String autowiredBeanName;
		Object instanceCandidate;
		// 如果找到多個元素,Spring要按一定的機制進行挑選,如果不滿足規則可能需要拋出異常
		if (matchingBeans.size() > 1) {
			// 按以下順序,找到符合條件的就直接返回
			// 1. 挑選出被標識爲primary的bean
			// 2. 挑選標識了@Priority,且先級級最高的bean。可以不標識,一旦標識,不允許同一優先級的存在
			// 3. fallback,依賴的名稱與matchingBeans中任意一Key匹配
			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			if (autowiredBeanName == null) {
				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
					// 非集合類,找到了多個符合條件的Bean,拋出異常
					return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
				}
				else {
					// In case of an optional Collection/Map, silently ignore a non-unique case:
					// possibly it was meant to be an empty collection of multiple regular beans
					// (before 4.3 in particular when we didn't even look for collection beans).
					return null;
				}
			}
			instanceCandidate = matchingBeans.get(autowiredBeanName);
		}
		else {
			// We have exactly one match.
			// 找到匹配的唯一元素,直接取出來
			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
			autowiredBeanName = entry.getKey();
			instanceCandidate = entry.getValue();
		}

		if (autowiredBeanNames != null) {
			// 將待裝配的Bean名稱放入autowiredBeanNames集合裏
			autowiredBeanNames.add(autowiredBeanName);
		}
		if (instanceCandidate instanceof Class) {
			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
		}
		Object result = instanceCandidate;
		if (result instanceof NullBean) {
			if (isRequired(descriptor)) {
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			result = null;
		}
		// 類型校驗,確保類型與解析出來的Bean實例能夠匹配
		if (!ClassUtils.isAssignableValue(type, result)) {
			throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
		}
		return result;
	}
	finally {
		ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
	}
}

本文案例是注入集合類對象,因此把關注點放到Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);

private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
		@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {

	// 依賴的類型
	final Class<?> type = descriptor.getDependencyType();

	if (descriptor instanceof StreamDependencyDescriptor) {
		// ...(特殊的用法,省略)
	}
	// 如果是數組
	else if (type.isArray()) {
		// 與下邊的分支邏輯類似
		Class<?> componentType = type.getComponentType();
		ResolvableType resolvableType = descriptor.getResolvableType();
		Class<?> resolvedArrayType = resolvableType.resolve(type);
		if (resolvedArrayType != type) {
			componentType = resolvableType.getComponentType().resolve();
		}
		if (componentType == null) {
			return null;
		}
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
				new MultiElementDescriptor(descriptor));
		if (matchingBeans.isEmpty()) {
			return null;
		}
		if (autowiredBeanNames != null) {
			autowiredBeanNames.addAll(matchingBeans.keySet());
		}
		TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
		Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
		if (result instanceof Object[]) {
			Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
			if (comparator != null) {
				Arrays.sort((Object[]) result, comparator);
			}
		}
		return result;
	}
	// 如果依賴的類型是Collection及其子接口(不能是具體實現類)
	else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
		// 獲取集合元素的泛型信息,即集合元素類型。如果沒有泛型信息,即獲取不了元素類型,則返回null
		Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
		if (elementType == null) {
			return null;
		}
		// 查找所有類型爲type的實例,存放在matchingBeans <beanName, bean>
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
				new MultiElementDescriptor(descriptor));
		if (matchingBeans.isEmpty()) {
			return null;
		}
		// 將待裝配的Bean名稱放入autowiredBeanNames集合裏
		if (autowiredBeanNames != null) {
			autowiredBeanNames.addAll(matchingBeans.keySet());
		}
		TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
		// 將解析出來的結果轉換成目標類型type的元素(List)
		Object result = converter.convertIfNecessary(matchingBeans.values(), type);
		if (result instanceof List) {
			// 如果待注入對象爲List實例,就再按AnnotationAwareOrderComparator排個序
			// 可用PriorityOrdered、Ordered、@Order、@Priority定義順序
			Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
			if (comparator != null) {
				((List<?>) result).sort(comparator);
			}
		}
		return result;
	}
	// 如果依賴的是Map類型(如: Map<String, BarService>)
	else if (Map.class == type) {
		ResolvableType mapType = descriptor.getResolvableType().asMap();
		Class<?> keyType = mapType.resolveGeneric(0);
		if (String.class != keyType) {
			// Map的Key必須爲String類型,表示Bean的名稱
			return null;
		}
		Class<?> valueType = mapType.resolveGeneric(1);
		// 同樣的,value類型的泛型信息必須指定,否則爲null
		if (valueType == null) {
			return null;
		}
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
				new MultiElementDescriptor(descriptor));
		if (matchingBeans.isEmpty()) {
			return null;
		}
		if (autowiredBeanNames != null) {
			autowiredBeanNames.addAll(matchingBeans.keySet());
		}
		// map無序,直接返回
		return matchingBeans;
	}
	else {
		return null;
	}
}

Array與Collection及其子接口的處理邏輯相似,都是找到matchingBeans,並通過TypeConverter轉換成目標類型,再經過AnnotationAwareOrderComparator排序,如此,返回的結集便是帶有順序的Array或Collection

Map的處理是找到matchingBeans,但不排序,此處需要注意的是,Key必須爲String類型,表示Bean的名稱。在本案例中,可寫成依賴的屬性是: Map<String, BarService>

doResolveDependencyresolveMultipleBeans方法中多次出現findAutowireCandidates的調用,它的作用是根據requiredType在IoC中找到匹配的Bean實例,並組裝成Map<BeanName, BeanInstance>返回,源碼如下:

protected Map<String, Object> findAutowireCandidates(
			@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
	// 從IoC中拿到所有類型爲requiredType的bean name,本質上調用的是ListableBeanFactory#getBeanNamesForType方法進行獲取
	String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
			this, requiredType, true, descriptor.isEager());
	Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
	
	// 處理特殊的依賴,如BeanFactory、ApplicationContext等,這些類的實例並不在狹義的IoC容器中,而是保存在resolvableDependencies
	// 只能通過遍歷resolvableDependencies與requiredType進行比較,滿足條件返返回
	for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
		Class<?> autowiringType = classObjectEntry.getKey();
		if (autowiringType.isAssignableFrom(requiredType)) {
			Object autowiringValue = classObjectEntry.getValue();
			autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
			if (requiredType.isInstance(autowiringValue)) {
				result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
				break;
			}
		}
	}
	// 本案例中candidateNames有兩個元素[barServiceImplOne、barServiceImplTwo]
	for (String candidate : candidateNames) {
		// 非自引用 且 candidate對應的BeanDefinition是autowireCandidate,則表明符合條件,添加到CandidateEntry中
		// 注:autowireCandidate是AbstractBeanDefinition的一個屬性,默認值爲true,即所有的Bean默認都支持autowire
		if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
			addCandidateEntry(result, candidate, descriptor, requiredType);
		}
	}
	if (result.isEmpty()) {
		boolean multiple = indicatesMultipleBeans(requiredType);
		// Consider fallback matches if the first pass failed to find anything...
		DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
		for (String candidate : candidateNames) {
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
					(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}
		if (result.isEmpty() && !multiple) {
			// Consider self references as a final pass...
			// but in the case of a dependency collection, not the very same bean itself.
			for (String candidate : candidateNames) {
				if (isSelfReference(beanName, candidate) &&
						(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
						isAutowireCandidate(candidate, fallbackDescriptor)) {
					addCandidateEntry(result, candidate, descriptor, requiredType);
				}
			}
		}
	}
	return result;
}



private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
		DependencyDescriptor descriptor, Class<?> requiredType) {

	if (descriptor instanceof MultiElementDescriptor) {
		// 下面的一行代碼本質上是: beanFactory.getBean(beanName), 即根據beanName上IoC容器中查找
		Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
		if (!(beanInstance instanceof NullBean)) {
			// 找到,添加進CandidateEntry中
			candidates.put(candidateName, beanInstance);
		}
	}
	else if (containsSingleton(candidateName) || (descriptor instanceof StreamDependencyDescriptor &&
			((StreamDependencyDescriptor) descriptor).isOrdered())) {
		// 同上
		Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
		candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
	}
	else {
		candidates.put(candidateName, getType(candidateName));
	}
}

需要說明一下的是,findAutowireCandidates方法中出現了resolvableDependencies(Map<Class<?>, Object>)屬性,它定義在DefaultListableBeanFactory,其作用是存放Spring內部一些特殊的Bean,比如BeanFactory、ResourceLoader、ApplicationContext、ServletRequest等;而一般普通的Bean存放在DefaultSingletonBeanRegistry.singletonObjects(Map<String, Object>)屬性中,該屬性就是狹義上的IoC容器

總結

AutowireCapableBeanFactory#resolveDependency,本質上是根據descriptor(依賴描述符)到Spring中找到符合描述的Bean(們)並返回。既可以解析由@Resouce標註的依賴信息,也可以解析由@Autowired、@Value標註的依賴信息;既可以解析單一依賴元素,也可以解析多個依賴(“集合類”)元素,當是集合類元素時,如果是Array或者是Collection,還可以根據PriorityOrdered、Ordered、@Order、@Priority定義注入的元素順序;既在狹義的IoC容器(singletonObjects)中尋找,也在特殊的容器(resolvableDependencies)中尋找。

總之,該方法的能力非常強大,涉及的面也非常地廣泛,因此,本文僅分享了其中一些與注入集合對象案例相關的細節。受限於作者的表達功力,本文並不足以描述它的全貌,還有諸多細節未能展開進行講解,例如:

  1. @Lazy是如何解析的?
  2. @Value的佔位符如何解析?SP EL表達式又如何解析?
  3. determineAutowireCandidate的細節是如何展開的?
  4. 類型轉換又是如何進行的?
  5. 該方法還支持哪些騷操作?

導讀:

AutowireCapableBeanFactory探密(1)——爲第三方框架賦能

AutowireCapableBeanFactory探密(2)——傳統裝配模式與現代註解驅動注入方式

發佈了15 篇原創文章 · 獲贊 2 · 訪問量 3226
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章