Spring源碼學習(四)在單值注入時如何按類型查找匹配的Bean

這是我學習Spring源碼以後的第四篇文章,若是你想了解,以前的3篇文章請您查閱:java

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

引言

我常常寫以下代碼:ui

@Autowired private AService aservice;

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

單值注入時如何按類型查找匹配的Bean

很簡單,核心就3步。.net

1.找到全部與類型匹配的bean,若是隻有一個直接返回。

Spring在DefaultListableBeanFactory.findAutowireCandidates方法中實現。 其部分源碼以下:code

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

這個beanNamesForTypeIncludingAncestors的做用就是,獲取requiredType(AService)類型全部匹配的beanName(包含先祖BeanFactory)。blog

beanNamesForTypeIncludingAncestors內部是若是實現的呢?我歸納了下簡要邏輯以下:ip

  • 遍歷全部的BeanDefinition,得到全部的BeanName.源碼學習

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

  • 匹配時,若是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日!!,祝你們節日快樂!

相關文章
相關標籤/搜索