这是我学习Spring源码之后的第四篇文章,如果你想了解,之前的3篇文章请您查阅:
前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日!!,祝大家节日快乐!