千家信息网

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

发表于:2024-12-05 作者:千家信息网编辑
千家信息网最后更新 2024年12月05日,Spring在单值注入时如何按类型查找匹配的Bean,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。引言我经常写如下代码:@Autowir
千家信息网最后更新 2024年12月05日Spring在单值注入时如何按类型查找匹配的Bean

Spring在单值注入时如何按类型查找匹配的Bean,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

引言

我经常写如下代码:

@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 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 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) ClassUtils.forName("javax.annotation.Priority", OrderUtils.class.getClassLoader());

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

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

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

看完上述内容,你们掌握Spring在单值注入时如何按类型查找匹配的Bean的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

0