专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

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

这是我学习Spring源码之后的第四篇文章,如果你想了解,之前的3篇文章请您查阅:

前3篇blog的地址:
[1、Spring源码学习(-)别怕,老外点中餐与AbstractBeanFactory.getBean的主流程差不多][1.Spring_-_AbstractBeanFactory.getBean]
[2、Spring源码学习(二)哎呦,按菜谱做菜与AbstractAutowireCapableBeanFactory.createBean流程差不多][2.Spring_AbstractAutowireCapableBeanFactory.createBean]
[3、pring源码学习(三)炒鸡丁与populateBean没区别][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的流程图

68_1.png

更加细致的部分,还是要自己看代码哦。

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

文章永久链接:https://tech.souyunku.com/35818

未经允许不得转载:搜云库技术团队 » Spring源码学习(四)在单值注入时如何按类型查找匹配的Bean

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们