前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring源码学习(四)在单值注入时如何按类型查找匹配的Bean 原

Spring源码学习(四)在单值注入时如何按类型查找匹配的Bean 原

作者头像
温安适
发布2019-10-06 20:56:22
1.7K0
发布2019-10-06 20:56:22
举报
文章被收录于专栏:温安适的blog温安适的blog

引言

我经常写如下代码:

代码语言:javascript
复制
@Autowired private AService aservice;

不知你是否也好奇,Spring是如果找到AService类型的Bean的呢?,此文,我们就聊聊这个->单值注入时如何按类型查找匹配的Bean.

单值注入时如何按类型查找匹配的Bean

很简单,核心就3步。

1.找到所有与类型匹配的bean,如果只有一个直接返回。

Spring在DefaultListableBeanFactory.findAutowireCandidates方法中实现。 其部分源码如下:

代码语言:javascript
复制
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的。源码如下:

代码语言:javascript
复制
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方法中。有如下逻辑。

代码语言:javascript
复制
//省略甚多代码...... 
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
   abd.setPrimary(true); 
} 
//省略很多代码....

看到这,我们可以得出一个结论:

被@Primary注解的bean,单值注入时会作为首选。

3.没有首选,按优先级选择,返回优选的Bean。

Spring是如何确定Bean的优先级的呢?

在DefaultListableBeanFactory.determineHighestPriorityCandidate中,实现按优先级选择Bean 其中,获取Bean的优先级的逻辑在getPriority方法中,如下:

代码语言:javascript
复制
protected Integer getPriority(Object beanInstance) { 
Comparator<Object> comparator = getDependencyComparator(); 
if (comparator instanceof OrderComparator) { 
	return ((OrderComparator) comparator).getPriority(beanInstance);
} 
	return null; 
}

查看OrderComparator的实现类AnnotationAwareOrderComparator中的源码发现, 获取优先级的逻辑实际在在OrderUtils.getPriority 中

代码语言:javascript
复制
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的值为:

代码语言:javascript
复制
priorityAnnotationType = (Class<? extends Annotation>) ClassUtils.forName("javax.annotation.Priority", OrderUtils.class.getClassLoader());

被@Priority注解的类,其值越小,在单值注入时,越优先选择。

Spring的源码非常多,仅有这3步当然是不行的,我准备了流程图,梳理了Spring单值注入时查找匹配Bean的流程。

单值注入时如何按类型查找匹配的Bean的流程图

下一篇想尝试写后处理,预计最晚10月13日!!,祝大家节日快乐!

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 单值注入时如何按类型查找匹配的Bean
    • 1.找到所有与类型匹配的bean,如果只有一个直接返回。
      • 2.多个Bean匹配时,有首选,返回首选的bean。
        • 3.没有首选,按优先级选择,返回优选的Bean。
        • 单值注入时如何按类型查找匹配的Bean的流程图
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档