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日!!,祝你们节日快乐!

相关文章
相关标签/搜索