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的邏輯
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日!!,祝