1. 程式人生 > >Spring原始碼學習(四)在單值注入時如何按型別查詢匹配的Bean

Spring原始碼學習(四)在單值注入時如何按型別查詢匹配的Bean

前3篇blog的地址:
1.Spring原始碼學習(-)別怕,老外點中餐與AbstractBeanFactory.getBean的主流程差不多
2.Spring原始碼學習(二)哎呦,按菜譜做菜與AbstractAutowireCapableBeanFactory.createBean流程差不多
3.pring原始碼學習(三)炒雞丁與populateBean沒區別

引言

我經常寫如下程式碼:

@Autowired private AService aservice;

不知你是否也好奇,Spring是如果找到AService型別的Bean的呢?,此文,我們就聊聊這個->單值注入時如何按型別查詢匹配的Bean.

單值注入時如何按型別查詢匹配的Bean

很簡單,核心就3步。

1.找到所有與型別匹配的bean,如果只有一個直接返回。

Spring在DefaultListableBeanFactory.findAutowireCandidates方法中實現。 其部分原始碼如下:

String[] candidateNames =
	BeanFactoryUtils .beanNamesForTypeIncludingAncestors
	( this, requiredType, true, descriptor.isEager());

這個beanNamesForTypeIncludingAncestors的作用就是,獲取requiredType(AService)型別所有匹配的beanName(包含先祖BeanFactory)。

beanNamesForTypeIncludingAncestors內部是如果實現的呢?我概括了下簡要邏輯如下:

  • 遍歷所有的BeanDefinition,獲得所有的BeanName.

  • 針對所有的BeanName,先嚐試獲取單例進行匹配,若未匹配上再以Bean Definition進行匹配。

  • 匹配時,如果Bean是FactoryBean,先嚐試FactoryBean生產的實際Bean進行匹配,若未匹配上再以FactoryBean 進行匹配。

2.多個Bean匹配時,有首選,返回首選的bean。

DefaultListableBeanFactory.determinePrimaryCandidate實現了篩選首選Bean的邏輯

, 其中的核心方法是isPrimary,該方法是判斷當前Bean是否是首選Bean的。原始碼如下:

protected boolean isPrimary(String beanName, Object beanInstance) { 
if (containsBeanDefinition(beanName)) { 
	return getMergedLocalBeanDefinition(beanName).isPrimary();
} 
BeanFactory parent = getParentBeanFactory(); 
	return (parent instanceof DefaultListableBeanFactory && ((DefaultListableBeanFactory) parent).isPrimary(beanName,beanInstance)); 
}

getMergedLocalBeanDefinition(beanName).isPrimary()方法,對應AbstractBeanDefinition的primary屬性,該屬性被賦值的地方是在AnnotatedBeanDefinitionReader.doRegisterBean方法中。有如下邏輯。

//省略甚多程式碼...... 
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
   abd.setPrimary(true); 
} 
//省略很多程式碼....

看到這,我們可以得出一個結論:

被@Primary註解的bean,單值注入時會作為首選。

3.沒有首選,按優先順序選擇,返回優選的Bean。

Spring是如何確定Bean的優先順序的呢?

在DefaultListableBeanFactory.determineHighestPriorityCandidate中,實現按優先順序選擇Bean 其中,獲取Bean的優先順序的邏輯在getPriority方法中,如下:

protected Integer getPriority(Object beanInstance) { 
Comparator<Object> comparator = getDependencyComparator(); 
if (comparator instanceof OrderComparator) { 
	return ((OrderComparator) comparator).getPriority(beanInstance);
} 
	return null; 
}

檢視OrderComparator的實現類AnnotationAwareOrderComparator中的原始碼發現, 獲取優先順序的邏輯實際在在OrderUtils.getPriority 中

public static Integer getPriority(Class<?> type) { 
if (priorityAnnotationType == null) {
 	return null;
} 
Object cached = priorityCache.get(type); 
if (cached != null) {
	return (cached instanceof Integer ? (Integer) cached : null);
}
Annotation priority = AnnotationUtils.findAnnotation(type, priorityAnnotationType);
Integer result = null; 
if (priority != null) { 
	result = (Integer) AnnotationUtils.getValue(priority);
} 
priorityCache.put(type, (result != null ? result : NOT_ANNOTATED)); 
return result;
}

在OrderUtils 向上查詢發現 priorityAnnotationType的值為:

priorityAnnotationType = (Class<? extends Annotation>) ClassUtils.forName("javax.annotation.Priority", OrderUtils.class.getClassLoader());

被@Priority註解的類,其值越小,在單值注入時,越優先選擇。

Spring的原始碼非常多,僅有這3步當然是不行的,我準備了流程圖,梳理了Spring單值注入時查詢匹配Bean的流程。

單值注入時如何按型別查詢匹配的Bean的流程圖

下一篇想嘗試寫後處理,預計最晚10月13日!!,祝