spring在帮我们管理bean的时候,会帮我们完成自动注入,其中有一个比较特殊的类型:list
这篇笔记主要记录spring注入list集合的原理

应用

public interface Rest {}@Component
public class RestServiceImpl01 implements Rest{}@Component
public class RestServiceImpl02 implements Rest{}@Component
public class OrderService {@Autowired//@Qualifierprivate List<Rest> restList;public void test() {System.out.println("打印注入的集合的值,restList:" + restList);}
}public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);OrderService orderService = ac.getBean(OrderService.class);orderService.test();}
}

以上代码执行之后,打印的结果是:

打印注入的集合的值,restList:[com.spring.list.RestServiceImpl01@60611244, com.spring.list.RestServiceImpl02@3745e5c6]

spring中,在使用@Autowired注解注入list集合的时候,并不会根据List类型去容器中查找,而是根据list集合的元素类型,从spring容器中找到所有的实现类,放在list集合中,然后注入到bean中

那如果我们想要指定只注入部分bean怎么办呢?

@Component
public class OrderService {@Autowired@Qualifierprivate List<Rest> restList;public void test() {System.out.println("打印注入的集合的值,restList:" + restList);}
}

只需要把这的@Qualifier注解放开,然后在需要注入的bean上,加上这个注解

@Component
@Qualifier
public class RestServiceImpl02 implements Rest{}

此时再运行代码:打印注入的集合的值,restList:[com.spring.list.RestServiceImpl02@d706f19]

所以这就是注入list集合bean的应用

原理

对于bean的注入,如果我们使用的是@Autowired注解,会被AutowiredAnnotationBeanPostProcessor处理

链路:

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertiesorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#injectorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValueorg.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependencyorg.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency

在doResolveDependency方法中,有一个代码逻辑

Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {return multipleBeans;
}

这里就是来解析list类型的

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveMultipleBeans
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();if (elementType == null) {return null;}// 在这里会取解析list集合中指定的接口所有的实现类Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,new MultiElementDescriptor(descriptor));if (matchingBeans.isEmpty()) {return null;}if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());}TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());Object result = converter.convertIfNecessary(matchingBeans.values(), type);if (getDependencyComparator() != null && result instanceof List) {((List<?>) result).sort(adaptDependencyComparator(matchingBeans));}return result;
}

在这个方法中,这段代码是来解析list集合的,所以只截取了这一部分代码,这一部分关键的代码是:findAutowireCandidates方法

protected Map<String, Object> findAutowireCandidates(@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {/*** 根据类型,获取当前beanDefinitionMap中的beanName,注意:这里是从beanDefinitionMap中获取的,并不是直接从spring* 容器中获取* 获取到的是待注入bean的name*/String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);/*** resolvableDependencies:这里来遍历这个集合,判断要注入的bean是否是该类型的* resolvableDependencies这个集合,默认有四个值* interface org.springframework.context.ApplicationContext" -> {AnnotationConfigApplicationContext@1641}* interface org.springframework.beans.factory.BeanFactory" -> {DefaultListableBeanFactory@1630}* interface org.springframework.core.io.ResourceLoader" -> {AnnotationConfigApplicationContext@1641} * interface org.springframework.context.ApplicationEventPublisher -> {AnnotationConfigApplicationContext@1641}*/for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {if (autowiringType.isAssignableFrom(requiredType)) {Object autowiringValue = this.resolvableDependencies.get(autowiringType);autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);if (requiredType.isInstance(autowiringValue)) {result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);break;}}}/*** 确切的说,是在isAutowireCandidate里面对Qualifier注解进行了判断*  org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isAutowireCandidate(org.springframework.beans.factory.config.BeanDefinitionHolder, org.springframework.beans.factory.config.DependencyDescriptor)*/for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {// Consider fallback matches if the first pass failed to find anything...DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}if (result.isEmpty()) {// Consider self references as a final pass...// but in the case of a dependency collection, not the very same bean itself.for (String candidate : candidateNames) {if (isSelfReference(beanName, candidate) &&(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&isAutowireCandidate(candidate, fallbackDescriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}}}return result;
}

在源码中,就是在isAutowireCandidate()这个方法中,对@Qualifier注解进行的过滤,也就是说,如果我们在注入list集合的时候,没有添加@Qualifier注解,那这个方法都会返回true,然后将所有的实现类都返回
如果加了@Qualifier注解,这里只有加了@Qualifier注解的实现类会返回TRUE,会被返回

这个方法的实现细节,待研究,debug看源码的时候,看到这样的结果

结论

所以,在spring中,我们在注入list集合的时候,如果只加了@Autowired注解,那就会把集合元素的所有实现类都注入进来,如果想只注入指定的类,那就使用@Qualifier注解

spring注入list集合相关推荐

  1. spring注入Map集合

    [例]spring注入Map集合 创建User类 package com.shw; public class User {private String username;private String ...

  2. Spring高级应用之注入各类集合

    先定义一个测试类,由于本文将要介绍注入各种集合时如何配置,故这个类包含各种集合,类名和属性名不好取,没有特殊含义: 1 2 3 4 5 6 7 8 9 publicclass Test {     p ...

  3. Spring 注入集合的成员变量属性

    Spring支持list,set,map和prop四种集合类型的注入. 看一个例子:JavaCollection这个类包含了上述介绍的4种集合类型的成员变量: import java.util.*; ...

  4. Spring 注入集合

    转载自   Spring 注入集合 注入集合 你已经看到了如何使用 value 属性来配置基本数据类型和在你的 bean 配置文件中使用<property>标签的 ref 属性来配置对象引 ...

  5. Spring框架中集合属性为对象的注入方法

    Spring框架中集合属性为对象的注入方法 前言 创建基础类 创建`Course`类 编写XML配置文件 创建测试类 执行结果 前言 在集合的属性注入中,如果注入属性为普通类型(String.int) ...

  6. ❤️Spring注入集合❤️(建议收藏)

    ❤️Spring注入集合 .以下是一些Spring常用的注入集合,请"食用",记得给个三连噢! 如果需要传递类似于 Java Collection 类型的值,例如 List.Set ...

  7. Spring框架教程集合

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development a ...

  8. 跟杨春娟学Spring笔记:集合装配

    跟杨春娟学Spring笔记:集合装配 完成:第一遍 1.常见集合元素有哪些? 集合元素 : 用途:装配list类型的值,允许重复 集合元素 : 用途:装配set类型的值,不允许重复 集合元素 : 用途 ...

  9. Spring注入(Injection)——教你一点一点知道什么是依赖注入及注入方式

    前言 在学习spring的时候有个很重的知识点,那就是注入,不同的注入方式为程序的运行效率,资源利用都有不同的好处,接下来就看看我通过看视频总结的注入. 一.引入注入 1.首先我们明确一个问题,什么注 ...

最新文章

  1. flowable 配置自定义表单_Flowable用代码自定义流程
  2. DataGrid/DataList封装操作函数库!
  3. 二分+并查集【bzoj3007】[SDOI2012]拯救小云公主
  4. vscode 设置断点知乎_vscode 代码自动换行设置
  5. 如何利用火狐获取网址中的提交链接
  6. 关于如何清除某个特定网站的缓存---基于Chrome浏览器
  7. 与java线程有关的,线程多少和什么有关?大神们表示有话要说!
  8. 展讯召开2017全球合作伙伴大会,发布两款新平台及新战略
  9. 写给准备学习Linux的人
  10. 数据分析项目:母婴商品销量分析
  11. MongoDB 4.0 RC 版本强势登陆
  12. NBA球星为啥那么多顶薪?数据可视化为你揭晓真相
  13. js获取注册表中应用程序的路径,并通过注册表打开
  14. NoSQL Scylla Open Source 3.0食量比Cassandra大
  15. Mac电脑怎么远程桌面连接?
  16. 基于单片机万用表量程手动自动电阻电流电压设计-全套资料
  17. python基础学习-反射
  18. 老年人也能解决智能技术困难问题
  19. 华为用linux系统装eclipse,centos装eclipse
  20. 涂鸦Zigbee SDK开发系列教程——4.烧录授权

热门文章

  1. 《把时间当做朋友》书摘
  2. thinkpad t450 无线网卡m2 ngff接口改装苹果网卡 黑苹果系统macOS
  3. 责任链模式(doFilter)的123、321原理
  4. 高地环境APP技术支持-Email:zcj331@163.com
  5. 解密:404背后的故事
  6. Linux必会100个命令(四十三)useradd和userdel
  7. PHP 中流行的 rpc 框架有哪些
  8. Python 常见文件格式 .py .pyc .pyw .pyo .pyd 之间的主要区别
  9. k8s istio 虚拟机重启后出现upstream connect error or disconnect
  10. 业余时间可以做什么兼职副业?盘点几个业余兼职副业方式