Spring 注入 List 集合详解:用法、原理与实战

 更新时间:2026年09月17日 10:50:00   作者:步行cgn  
Spring注入List 集合的核心机制是:‌自动收集容器中所有匹配类型的 Bean,组装成一个List 注入‌,而不是按 List 类型本身去查找,‌‌本文介绍Spring注入List 集合的相关知识,感兴趣的朋友一起看看吧

一、什么是 List 注入?

List 注入是指将一个 List 类型的集合注入到 Bean 的属性中。与数组注入不同,List 更灵活——元素可以动态增删,支持泛型,是 Spring 开发中处理多个同类型依赖的首选方式。

@Component
public class MyBean {
    private List<String> servers;          // 字符串 List
    private List<DataSource> dataSources;  // Bean List
    private List<Handler> handlers;        // 策略/处理器 List
}

二、XML 配置中注入 List

2.1 注入字符串 List

<bean id="myBean" class="com.example.MyBean">
    <property name="servers">
        <list>
            <value>server1.example.com</value>
            <value>server2.example.com</value>
            <value>server3.example.com</value>
        </list>
    </property>
</bean>

2.2 注入 Bean List

<bean id="myBean" class="com.example.MyBean">
    <property name="dataSources">
        <list>
            <ref bean="dataSource1"/>
            <ref bean="dataSource2"/>
            <ref bean="dataSource3"/>
        </list>
    </property>
</bean>

2.3 注入基本类型 List

<bean id="myBean" class="com.example.MyBean">
    <property name="ports">
        <list>
            <value>8080</value>
            <value>8081</value>
            <value>8082</value>
        </list>
    </property>
</bean>

Spring 会自动将字符串值转换为 Integer 类型。

2.4 注入嵌套 List

<bean id="myBean" class="com.example.MyBean">
    <property name="matrix">
        <list>
            <list>
                <value>1</value>
                <value>2</value>
            </list>
            <list>
                <value>3</value>
                <value>4</value>
            </list>
        </list>
    </property>
</bean>

对应 Java:

private List<List<Integer>> matrix;

2.5 注入对象 List

<bean id="myBean" class="com.example.MyBean">
    <property name="users">
        <list>
            <bean class="com.example.User">
                <property name="name" value="张三"/>
                <property name="age" value="25"/>
            </bean>
            <bean class="com.example.User">
                <property name="name" value="李四"/>
                <property name="age" value="30"/>
            </bean>
        </list>
    </property>
</bean>

2.6 List 与 Array 的 XML 差异

<!-- List 类型属性 -->
<property name="servers">
    <list>
        <value>server1</value>
        <value>server2</value>
    </list>
</property>
<!-- Array 类型属性(Spring 会自动转换) -->
<property name="servers">
    <array>
        <value>server1</value>
        <value>server2</value>
    </array>
</property>

虽然 <list><array> 语义不同,但对 List 类型的属性来说,两者都能使用。

三、@Value 注入 List

3.1 从配置文件读取

@Component
public class MyBean {
    // 配置文件:app.servers=server1,server2,server3
    @Value("${app.servers}")
    private List<String> servers;
    // 带默认值
    @Value("${app.ports:8080,8081,8082}")
    private List<Integer> ports;
}

配置文件:

app:
  servers: server1,server2,server3
  ports: 8080,8081,8082

Spring 会自动将逗号分隔的字符串拆分为 List。

3.2 使用 SpEL 拆分

当值中包含逗号或需要更复杂的拆分逻辑时,用 SpEL:

@Value("#{'${app.servers}'.split(',')}")
private List<String> servers;
@Value("#{'${app.servers:server1,server2}'.split(',')}")
private List<String> serversWithDefault;

3.3 直接指定多个值

@Value("server1,server2,server3")
private List<String> servers;

四、@ConfigurationProperties 绑定 List

4.1 简单 List

@Component
@ConfigurationProperties(prefix = "app")
@Getter
@Setter
public class AppProperties {
    private List<String> servers;
    private List<Integer> ports;
}
app:
  servers:
    - server1
    - server2
    - server3
  ports: [8080, 8081, 8082]

4.2 对象 List

@Component
@ConfigurationProperties(prefix = "app")
@Getter
@Setter
public class AppProperties {
    private List<User> users;
    
    @Getter
    @Setter
    public static class User {
        private String name;
        private int age;
        private String email;
    }
}
app:
  users:
    - name: 张三
      age: 25
      email: zhangsan@example.com
    - name: 李四
      age: 30
      email: lisi@example.com

4.3 嵌套 List

@Component
@ConfigurationProperties(prefix = "app")
@Getter
@Setter
public class AppProperties {
    private List<Cluster> clusters;
    @Getter
    @Setter
    public static class Cluster {
        private String name;
        private List<String> nodes;  // 嵌套 List
    }
}
app:
  clusters:
    - name: cluster-a
      nodes:
        - node1
        - node2
    - name: cluster-b
      nodes:
        - node3
        - node4

4.4 List + Map 组合

@Component
@ConfigurationProperties(prefix = "app")
@Getter
@Setter
public class AppProperties {
    private List<Database> databases;
    @Getter
    @Setter
    public static class Database {
        private String type;
        private Map<String, String> config;  // List 中嵌套 Map
    }
}
app:
  databases:
    - type: mysql
      config:
        url: jdbc:mysql://localhost:3306/db1
        username: root
    - type: postgresql
      config:
        url: jdbc:postgresql://localhost:5432/db2
        username: admin

五、自动注入 Bean List(最常用)

Spring 支持将容器中所有同类型的 Bean 自动注入到 List 中,这是策略模式在 Spring 中的经典应用。

5.1 基本用法

public interface PaymentStrategy {
    void pay(double amount);
}
@Component
public class AliPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount);
    }
}
@Component
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount);
    }
}
@Component
public class PaymentService {
    @Autowired
    private List<PaymentStrategy> strategies;  // 自动注入所有实现
    public void payAll(double amount) {
        strategies.forEach(s -> s.pay(amount));
    }
}

5.2 构造器注入 List

@Service
public class PaymentService {
    private final List<PaymentStrategy> strategies;
    public PaymentService(List<PaymentStrategy> strategies) {
        this.strategies = strategies;
    }
}

5.3 使用 @Order 控制顺序

@Component
@Order(1)
public class FirstStrategy implements PaymentStrategy { }
@Component
@Order(2)
public class SecondStrategy implements PaymentStrategy { }
@Component
@Order(3)
public class ThirdStrategy implements PaymentStrategy { }

注入的 List 中,元素按 @Order 的值从小到大排列。也可以用 Ordered 接口:

@Component
public class FirstStrategy implements PaymentStrategy, Ordered {
    @Override
    public int getOrder() {
        return 1;
    }
}

5.4 策略模式实战:按名称分发

public interface PaymentStrategy {
    String getName();
    void pay(double amount);
}
@Component
public class AliPayStrategy implements PaymentStrategy {
    @Override
    public String getName() { return "alipay"; }
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount);
    }
}
@Component
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public String getName() { return "wechat"; }
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount);
    }
}
@Service
public class PaymentService {
    private final Map<String, PaymentStrategy> strategyMap;
    public PaymentService(List<PaymentStrategy> strategies) {
        this.strategyMap = strategies.stream()
            .collect(Collectors.toMap(PaymentStrategy::getName, s -> s));
    }
    public void pay(String type, double amount) {
        PaymentStrategy strategy = strategyMap.get(type);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的支付方式:" + type);
        }
        strategy.pay(amount);
    }
}

六、List 为空时的处理

6.1 默认行为

当容器中没有匹配类型的 Bean 时,@Autowired 注入 List 不会抛异常,而是注入一个空 List。

@Autowired
private List<Handler> handlers;  // 没有 Handler 时,注入空 List(不是 null)

这与数组注入不同——数组注入在找不到 Bean 时会抛异常,而 List 注入会返回空集合。

6.2 使用 ObjectProvider 控制

@Autowired
private ObjectProvider<List<Handler>> handlersProvider;
public void doSomething() {
    List<Handler> handlers = handlersProvider.getIfAvailable(Collections::emptyList);
    // 使用 handlers
}

6.3 校验 List 不为空

@PostConstruct
public void init() {
    if (strategies.isEmpty()) {
        throw new IllegalStateException("没有可用的策略实现");
    }
}

七、List 注入 vs 数组注入 vs Map 注入

对比维度List数组Map
类型List<T>T[]Map<String, T>
长度可变固定可变
找不到 Bean 时注入空 List抛异常(默认)注入空 Map
排序@Order@Order
按名称查找需手动转换需手动转换直接按 key 获取
适用场景需要顺序、遍历处理固定长度、性能敏感需要按名称查找

Map 注入的用法:

@Autowired
private Map<String, PaymentStrategy> strategyMap;

Spring 会自动将 Bean 名称作为 key,Bean 实例作为 value 注入到 Map 中。这种方式在策略模式中比 List 更方便——直接按名称获取策略,不需要遍历。

八、常见问题

8.1 List 注入为 null

原因:没有使用 @Autowired 或没有 @Component 注解,或者类没有被 Spring 管理。

解决:确保类被 Spring 管理,字段标注 @Autowired

8.2 List 顺序不符合预期

原因:多个 Bean 注入 List 时,默认顺序是 Bean 定义的顺序。

解决:使用 @Order 注解明确指定顺序。

8.3 @Value 注入 List 时逗号被拆分

原因:配置值中的逗号被当作分隔符。

解决:使用 @ConfigurationProperties 绑定,或用 SpEL 自定义拆分:

@Value("#{'${app.servers}'.split(';')}")  // 用分号分隔
private List<String> servers;

8.4 List 中混入 null

XML 配置中可以用 <null/> 注入 null 元素:

<list>
    <value>server1</value>
    <null/>
    <value>server3</value>
</list>

但建议避免在 List 中放入 null,容易导致空指针。

8.5 List 注入与 @Qualifier 冲突

@Qualifier 用于指定单个 Bean 的名称,不能用于筛选 List 中的 Bean。如果需要按条件筛选 Bean,使用 @Bean 方法手动组装,或使用 ObjectProvider

九、最佳实践

优先使用自动注入 List。 当需要收集同一接口的所有实现时,@Autowired List<T> 是最简洁的方式,天然支持策略模式。

用 @Order 控制顺序。 当 List 中的元素有执行顺序要求时,给实现类加 @Order 注解。

考虑使用 Map 代替 List。 如果主要目的是按名称获取特定策略,直接注入 Map<String, T> 更方便。

配置文件中的 List 用 @ConfigurationProperties。@Value 更类型安全,支持嵌套对象。

处理空 List。 虽然 List 注入不会抛异常,但空集合可能导致业务逻辑出错。在 @PostConstruct 中校验关键 List 是否为空。

十、总结

维度核心要点
XML 注入使用 <list> 标签,支持嵌套、对象、基本类型
@Value 注入逗号分隔字符串自动拆分,或使用 SpEL 自定义拆分
@ConfigurationProperties原生支持复杂 List 绑定,推荐用于配置文件
自动注入 Bean List注入容器中所有同类型 Bean,策略模式的经典实现
顺序控制@Order 注解或 Ordered 接口
空 List 处理默认注入空集合,需要时用 ObjectProvider@PostConstruct 校验
List vs MapList 适合遍历,Map 适合按名称查找
最佳实践自动注入用 List,配置绑定用 @ConfigurationProperties,按名称用 Map

List 注入是 Spring 中最常用的集合注入方式。它天然支持策略模式,让“收集所有实现类”变得极其简单。掌握 List 注入的各种方式,能让你在业务开发中灵活处理多实现、多配置的场景。

到此这篇关于Spring 注入 List 集合详解的文章就介绍到这了,更多相关Spring 注入 List 集合内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringCache 缓存使用方案总结

    SpringCache 缓存使用方案总结

    在基于SpringBoot3.x集成JetCache时遇到问题,决定采用SpringCache作为替代方案,本文详细介绍了SpringCache本地缓存(Caffeine)和本地+远程(Redis)混合缓存的配置和使用方法,并总结了常用的缓存注解参数及其含义,感兴趣的朋友跟随小编一起看看吧
    2026-02-02
  • java实现滑动验证解锁

    java实现滑动验证解锁

    这篇文章主要为大家详细介绍了java实现滑动验证解锁,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • SpringCloud实现灰度发布的方法步骤

    SpringCloud实现灰度发布的方法步骤

    本文主要介绍了SpringCloud实现灰度发布的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Spring配置文件使用占位符配置方式

    Spring配置文件使用占位符配置方式

    这篇文章主要介绍了Spring配置文件使用占位符配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • springboot基于docsify 实现随身文档

    springboot基于docsify 实现随身文档

    这篇文章主要介绍了springboot基于docsify实现随身文档的相关资料,需要的朋友可以参考下
    2022-09-09
  • Java中synchronized锁的深入理解

    Java中synchronized锁的深入理解

    这篇本文主要对Java中synchronized锁进行深入理解,文中通过synchronized的优化,synchronized的实现原理及synchronized的升级过程来介绍Java中synchronized锁,感兴趣的同学可以跟着小编一起来学习
    2023-05-05
  • SpringMVC4.3 HttpMessageConverter接口实现源码分析

    SpringMVC4.3 HttpMessageConverter接口实现源码分析

    这篇文章主要为大家介绍了SpringMVC4.3 HttpMessageConverter接口实现源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • SpringBoot Event 事件如何实现异步延迟执行

    SpringBoot Event 事件如何实现异步延迟执行

    这篇文章主要介绍了Spring Boot Event 事件如何实现异步延迟执行问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Jenkins节点配置实现原理及过程解析

    Jenkins节点配置实现原理及过程解析

    这篇文章主要介绍了Jenkins节点配置实现原理及过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Java ArrayList的基本概念和作用及动态数组的机制与性能

    Java ArrayList的基本概念和作用及动态数组的机制与性能

    在Java中,ArrayList是一个实现了List接口的动态数组,它可以根据需要自动增加大小,因此可以存储任意数量的元素,这篇文章主要介绍了探秘Java ArrayList的基本概念和作用及动态数组的机制与性能,需要的朋友可以参考下
    2023-12-12

最新评论