前情回顧
在前兩篇文章中音榜,多次提及AutowireCapableBeanFactory#resolveDependency
方法,原因是該方法很重要,在Spring很多場合都涉及該方法的調(diào)用,包括但不限于以下場景:
- 解析@Resouce注解的元素(CommonAnnotationBeanPostProcessor#autowireResource)
- 解析@Autowired、@Value注解的元素(AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject埠偿、AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject)
- autowire = byType(AbstractAutowireCapableBeanFactory#autowireByType)
- 構(gòu)造器裝配(ConstructorResolver#resolveAutowiredArgument)
了解此方法的底層工作原理,有助于提升對(duì)Spring Bean解析的認(rèn)知能力
案例
本文以一種經(jīng)典的注入案例進(jìn)行探討:注入集合對(duì)象
// 接口
public interface BarService {}
// 實(shí)現(xiàn)類1
@Service
public class BarServiceImplOne implements BarService {}
// 實(shí)現(xiàn)類2
@Service
public class BarServiceImplTwo implements BarService {}
@Service
public class FooService {
// barServices集合有兩個(gè)元素榜晦,分別是BarServiceImplOne冠蒋、BarServiceImplTwo
@Resource
private List<BarService> barServices;
}
注入集合的姿勢Spring官網(wǎng)就有介紹,開發(fā)中也比較常用乾胶,現(xiàn)在借助該方式來探尋其中的一些細(xì)節(jié)問題抖剿,并介紹resolveDependency
在其中起了怎樣的作用
源碼分析
源碼基于Spring 5.1.11.RELEASE
resolveDependency
翻譯成中文即是解析依賴朽寞,其方法簽名如下:
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
- descriptor: 依賴描述符,它描述了一個(gè)待注入的依賴信息:要么是構(gòu)造器參數(shù)斩郎,要么是方法參數(shù)脑融,要么是字段,并且提供了非常友好的缩宜、一種統(tǒng)一的方式去訪問
- requestingBeanName: 聲明依賴的Bean肘迎。舉例,如果A依賴B锻煌,則requestingBeanName表示的是A
- autowiredBeanNames: 待裝配的Bean名稱列表膜宋,即解析出來的bean names。使用上炼幔,一般是由外部傳進(jìn)來一個(gè)空的集合,在方法內(nèi)部進(jìn)行Bean的解析史简,如果符合條件乃秀,就將該bean name添加到集合內(nèi)。潛臺(tái)詞是圆兵,可能會(huì)有多個(gè)符合條件的Bean跺讯,其實(shí)也很好理解,如果被依賴的類(接口)有多個(gè)實(shí)現(xiàn)類殉农,且都被Spring管理刀脏,就存在多個(gè)符合條件的Bean的可能性
- typeConverter: 類型轉(zhuǎn)化器,用于類型轉(zhuǎn)換
由于使用的是@Resouce注解超凳,故直接定位到CommonAnnotationBeanPostProcessor#autowireResource
愈污,AutowireCapableBeanFactory探密(2)——傳統(tǒng)裝配模式與現(xiàn)代注解驅(qū)動(dòng)注入方式一文中也有簡單的介紹
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)) {
// 滿足條件,進(jìn)入該分支
// 空集合
autowiredBeanNames = new LinkedHashSet<>();
// 進(jìn)行Bean解析, requestingBeanName: fooService
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
// ...(省略)
}
接著調(diào)用beanFactory.resolveDependency
// DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 初始化參數(shù)解析器
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 處理依賴類型為Option類的case轮傍,很顯然暂雹,需要JDK1.8以上才支持,一般不會(huì)進(jìn)入此處
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%的情況進(jìn)入else的分支
else {
// 處理@Lazy 注解的情況驰吓,一般特殊需要才會(huì)在字段或方法上標(biāo)注@Lazy涧尿,不是本文重點(diǎn),略過
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 大部分情況會(huì)走下面的case檬贰,進(jìn)行真正的解析
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
雖然有很多條件分支存在姑廉,但大部分場景都不會(huì)用到,因此只需要關(guān)注result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
這一行核心代碼即可
有意思的是偎蘸,一些人認(rèn)為Spring考慮周全庄蹋,兼容各種case瞬内,360度無死角,正是Java web領(lǐng)域它獨(dú)領(lǐng)風(fēng)騷的魅力之所在限书;與此同時(shí)虫蝶,另一些人認(rèn)為正是因?yàn)榭紤]太周全,Spring變的越來越臃腫不堪倦西,代碼閱讀越發(fā)困難能真,需要瘦瘦身,甚至需要一個(gè)更輕量級(jí)的框架來替代扰柠。天下大勢粉铐,分久必合,合久必分卤档,蒼天饒過誰蝙泼?
整體上看一下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實(shí)現(xiàn)了resolveShortcut方法,返回了非空值劝枣。目前版本代碼只在AutowiredFieldElement汤踏、AutowiredMethodElement類中使用到,也即是說舔腾,只有解析@Autowired溪胶、@Value注解的元素才會(huì)用到,目的是為了將解析結(jié)果緩存起來稳诚,避免重復(fù)解析
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 依賴的類型type: java.util.List
Class<?> type = descriptor.getDependencyType();
// 處理@Value注解哗脖,取值注解中的value屬性中的值(原樣,未經(jīng)過解析的)扳还,如果descriptor未被@Value標(biāo)注才避,則返回null
// 注:從此處可知,@Value注解的優(yōu)先級(jí)較高氨距,只要找到了就處理工扎,不再往下走
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 處理占位符如${},做占位符的替換(不解析SP EL表達(dá)式)
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 {
// 類型轉(zhuǎn)換衔蹲,把解析出來的結(jié)果轉(zhuǎn)成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()));
}
}
// 本文重點(diǎn)肢娘,解析"集合類"Bean,如果依賴的類型不是"集合類"舆驶,則返回null
// 注:"集合類"是口語描述橱健,目的是方便記憶,實(shí)際上沙廉,還支持?jǐn)?shù)組類型和Map類型
/**
* 1. array
* 2. Collection及其子類
* 3. Map
*/
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 代碼走到此處拘荡,說明依賴的是非"集合類",
// 查找所有類型為type的實(shí)例撬陵,存放在matchingBeans <beanName, bean>
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 如果IoC容器中找不到符合條件的Bean珊皿,且依賴項(xiàng)標(biāo)識(shí)為required网缝,則拋出NoSuchBeanDefinitionException異常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 如果找到多個(gè)元素,Spring要按一定的機(jī)制進(jìn)行挑選蟋定,如果不滿足規(guī)則可能需要拋出異常
if (matchingBeans.size() > 1) {
// 按以下順序粉臊,找到符合條件的就直接返回
// 1. 挑選出被標(biāo)識(shí)為primary的bean
// 2. 挑選標(biāo)識(shí)了@Priority,且先級(jí)級(jí)最高的bean驶兜《笾伲可以不標(biāo)識(shí),一旦標(biāo)識(shí)抄淑,不允許同一優(yōu)先級(jí)的存在
// 3. fallback屠凶,依賴的名稱與matchingBeans中任意一Key匹配
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 非集合類,找到了多個(gè)符合條件的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;
}
// 類型校驗(yàn),確保類型與解析出來的Bean實(shí)例能夠匹配
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
本文案例是注入集合類對(duì)象郑原,因此把關(guān)注點(diǎn)放到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) {
// ...(特殊的用法贱枣,省略)
}
// 如果是數(shù)組
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及其子接口(不能是具體實(shí)現(xiàn)類)
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
// 獲取集合元素的泛型信息,即集合元素類型颤专。如果沒有泛型信息,即獲取不了元素類型钠乏,則返回null
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
// 查找所有類型為type的實(shí)例栖秕,存放在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());
// 將解析出來的結(jié)果轉(zhuǎn)換成目標(biāo)類型type的元素(List)
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (result instanceof List) {
// 如果待注入對(duì)象為List實(shí)例,就再按AnnotationAwareOrderComparator排個(gè)序
// 可用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轉(zhuǎn)換成目標(biāo)類型搞隐,再經(jīng)過AnnotationAwareOrderComparator排序驹愚,如此,返回的結(jié)集便是帶有順序的Array或Collection
Map的處理是找到matchingBeans劣纲,但不排序逢捺,此處需要注意的是,Key必須為String類型癞季,表示Bean的名稱劫瞳。在本案例中倘潜,可寫成依賴的屬性是: Map<String, BarService>
在doResolveDependency
與resolveMultipleBeans
方法中多次出現(xiàn)findAutowireCandidates
的調(diào)用,它的作用是根據(jù)requiredType
在IoC中找到匹配的Bean實(shí)例志于,并組裝成Map<BeanName, BeanInstance>
返回涮因,源碼如下:
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 從IoC中拿到所有類型為requiredType的bean name,本質(zhì)上調(diào)用的是ListableBeanFactory#getBeanNamesForType方法進(jìn)行獲取
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 處理特殊的依賴恨憎,如BeanFactory蕊退、ApplicationContext等,這些類的實(shí)例并不在狹義的IoC容器中憔恳,而是保存在resolvableDependencies
// 只能通過遍歷resolvableDependencies與requiredType進(jìn)行比較瓤荔,滿足條件返返回
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有兩個(gè)元素[barServiceImplOne、barServiceImplTwo]
for (String candidate : candidateNames) {
// 非自引用 且 candidate對(duì)應(yīng)的BeanDefinition是autowireCandidate钥组,則表明符合條件输硝,添加到CandidateEntry中
// 注:autowireCandidate是AbstractBeanDefinition的一個(gè)屬性,默認(rèn)值為true程梦,即所有的Bean默認(rèn)都支持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) {
// 下面的一行代碼本質(zhì)上是: beanFactory.getBean(beanName), 即根據(jù)beanName上IoC容器中查找
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
if (!(beanInstance instanceof NullBean)) {
// 找到点把,添加進(jìn)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方法中出現(xiàn)了resolvableDependencies(Map<Class<?>, Object>)屬性屿附,它定義在DefaultListableBeanFactory郎逃,其作用是存放Spring內(nèi)部一些特殊的Bean,比如BeanFactory挺份、ResourceLoader褒翰、ApplicationContext、ServletRequest等匀泊;而一般普通的Bean存放在DefaultSingletonBeanRegistry.singletonObjects(Map<String, Object>)屬性中优训,該屬性就是狹義上的IoC容器
總結(jié)
AutowireCapableBeanFactory#resolveDependency,本質(zhì)上是根據(jù)descriptor(依賴描述符)到Spring中找到符合描述的Bean(們)并返回各聘。既可以解析由@Resouce標(biāo)注的依賴信息揣非,也可以解析由@Autowired、@Value標(biāo)注的依賴信息躲因;既可以解析單一依賴元素早敬,也可以解析多個(gè)依賴("集合類")元素,當(dāng)是集合類元素時(shí)大脉,如果是Array或者是Collection搁嗓,還可以根據(jù)PriorityOrdered、Ordered箱靴、@Order腺逛、@Priority定義注入的元素順序;既在狹義的IoC容器(singletonObjects)中尋找衡怀,也在特殊的容器(resolvableDependencies)中尋找棍矛。
總之安疗,該方法的能力非常強(qiáng)大,涉及的面也非常地廣泛够委,因此荐类,本文僅分享了其中一些與注入集合對(duì)象案例相關(guān)的細(xì)節(jié)。受限于作者的表達(dá)功力茁帽,本文并不足以描述它的全貌玉罐,還有諸多細(xì)節(jié)未能展開進(jìn)行講解,例如:
- @Lazy是如何解析的潘拨?
- @Value的占位符如何解析吊输?SP EL表達(dá)式又如何解析?
- determineAutowireCandidate的細(xì)節(jié)是如何展開的铁追?
- 類型轉(zhuǎn)換又是如何進(jìn)行的季蚂?
- 該方法還支持哪些騷操作?
導(dǎo)讀:
AutowireCapableBeanFactory探密(1)——為第三方框架賦能
AutowireCapableBeanFactory探密(2)——傳統(tǒng)裝配模式與現(xiàn)代注解驅(qū)動(dòng)注入方式