8人参与 • 2026-09-17 • Java
set 注入是指将一个 set 类型的集合注入到 bean 的属性中。set 与 list 最大的区别是:set 中的元素不允许重复,且通常不保证顺序(除非使用 linkedhashset 或 treeset)。
@component
public class mybean {
private set<string> servers; // 字符串 set
private set<datasource> datasources; // bean set
private set<handler> handlers; // 策略/处理器 set
}
在 spring 注入场景中,set 常用于:
<bean id="mybean" class="com.example.mybean">
<property name="servers">
<set>
<value>server1.example.com</value>
<value>server2.example.com</value>
<value>server3.example.com</value>
</set>
</property>
</bean><bean id="mybean" class="com.example.mybean">
<property name="datasources">
<set>
<ref bean="datasource1"/>
<ref bean="datasource2"/>
<ref bean="datasource3"/>
</set>
</property>
</bean><bean id="mybean" class="com.example.mybean">
<property name="ports">
<set>
<value>8080</value>
<value>8081</value>
<value>8082</value>
</set>
</property>
</bean>spring 会自动将字符串值转换为 integer 类型。
<bean id="mybean" class="com.example.mybean">
<property name="users">
<set>
<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>
</set>
</property>
</bean><!-- set 类型属性 -->
<property name="servers">
<set>
<value>server1</value>
<value>server2</value>
</set>
</property>
<!-- list 类型属性 -->
<property name="servers">
<list>
<value>server1</value>
<value>server2</value>
</list>
</property>虽然 xml 标签不同,但 spring 会根据目标属性的类型自动选择合适的集合实现。如果属性是 set,即使写 <list>,spring 也会注入 set(通常是 linkedhashset)。
@component
public class mybean {
// 配置文件:app.servers=server1,server2,server3
@value("${app.servers}")
private set<string> servers;
// 带默认值
@value("${app.ports:8080,8081,8082}")
private set<integer> ports;
}
配置文件:
app: servers: server1,server2,server3 ports: 8080,8081,8082
spring 会自动将逗号分隔的字符串拆分为 set。
@value("#{'${app.servers}'.split(',')}")
private set<string> servers;
注意:split() 返回数组,spring 会自动转换为 set。如果数组中有重复元素,set 会自动去重。
@value("server1,server2,server3")
private set<string> servers;
@component
@configurationproperties(prefix = "app")
@getter
@setter
public class appproperties {
private set<string> servers;
private set<integer> ports;
}
app:
servers:
- server1
- server2
- server3
ports: [8080, 8081, 8082]@component
@configurationproperties(prefix = "app")
@getter
@setter
public class appproperties {
private set<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@component
@configurationproperties(prefix = "app")
@getter
@setter
public class appproperties {
private set<cluster> clusters;
@getter
@setter
public static class cluster {
private string name;
private set<string> nodes; // 嵌套 set
}
}
app:
clusters:
- name: cluster-a
nodes:
- node1
- node2
- name: cluster-b
nodes:
- node3
- node4spring 支持将容器中所有同类型的 bean 自动注入到 set 中。
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 set<paymentstrategy> strategies; // 自动注入所有实现
public void payall(double amount) {
strategies.foreach(s -> s.pay(amount));
}
}
@service
public class paymentservice {
private final set<paymentstrategy> strategies;
public paymentservice(set<paymentstrategy> strategies) {
this.strategies = strategies;
}
}
spring 注入 set 时,默认使用 linkedhashset。linkedhashset 内部维护了一个链表,保留了元素的插入顺序,因此注入到 set 中的 bean 顺序通常是 bean 定义的顺序。
如果需要去重且不关心顺序,可以声明为 set。如果需要排序,可以声明为 sortedset 或 treeset:
@autowired private sortedset<paymentstrategy> strategies; // 按自然顺序排序 @autowired private treeset<paymentstrategy> strategies; // 按 comparator 或自然顺序
虽然 set 通常不保证顺序,但 linkedhashset 会保留插入顺序。配合 @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 { }
注入的 linkedhashset 中,元素按 @order 的值从小到大排列。
set 最重要的特性是元素去重。当容器中有多个相同类型的 bean 时,如果 bean 的 equals() 和 hashcode() 判定为相同,set 会自动去重。
@component
public class handlera implements handler {
@override
public boolean equals(object obj) {
return obj instanceof handlera;
}
@override
public int hashcode() {
return handlera.class.hashcode();
}
}
@component
public class handlera2 implements handler {
// 如果 equals 和 hashcode 与 handlera 相同,set 会去重
}
但在实际开发中,不同的 bean 通常不会互相 equals,所以 set 注入的去重效果主要体现在同一个 bean 被多次注册的场景(比如通过不同的配置方式重复注册)。
当容器中没有匹配类型的 bean 时,@autowired 注入 set 不会抛异常,而是注入一个空 set。
@autowired private set<handler> handlers; // 没有 handler 时,注入空 set(不是 null)
这与 list 注入行为一致。数组注入在找不到 bean 时会抛异常,而 set 和 list 会返回空集合。
@autowired
private objectprovider<set<handler>> handlersprovider;
public void dosomething() {
set<handler> handlers = handlersprovider.getifavailable(collections::emptyset);
}
@postconstruct
public void init() {
if (strategies.isempty()) {
throw new illegalstateexception("没有可用的策略实现");
}
}
| 对比维度 | set | list | 数组 |
|---|---|---|---|
| 是否去重 | ✅ 自动去重 | ❌ 允许重复 | ❌ 允许重复 |
| 是否有序 | ⚠️ 取决于实现类 | ✅ 有序 | ✅ 有序 |
| 默认实现 | linkedhashset | arraylist | 无 |
| 找不到 bean 时 | 注入空 set | 注入空 list | 抛异常 |
| 排序支持 | 支持 @order(linkedhashset) | 支持 @order | 支持 @order |
| 适用场景 | 需要去重的多实现 | 需要顺序遍历 | 固定长度、性能敏感 |
选择建议:
spring 在 populatebean() 阶段处理 set 注入时,会根据目标属性的类型选择合适的集合实现类。
简化流程:
set<paymentstrategy> 类型的依赖defaultlistablebeanfactory.resolvemultiplebeans() 获取所有 paymentstrategy 类型的 beanset 选择合适的实现类(默认 linkedhashset)如果 bean 的数量为 0,返回空 set,不抛异常。
原因:没有使用 @autowired 或没有 @component 注解。
解决:确保类被 spring 管理,字段标注 @autowired。
原因:hashset 不保证顺序,如果 spring 注入的是 linkedhashset,则按 bean 定义的顺序。
解决:使用 @order 注解明确顺序,或声明为 sortedset、treeset。
原因:多个 bean 的 equals() 和 hashcode() 判定为相同,set 自动去重。
解决:检查 bean 的 equals() 和 hashcode() 实现,避免误判。如果不希望去重,改用 list 或数组。
原因:配置值中的逗号被当作分隔符。
解决:使用 @configurationproperties 绑定,或用 spel 自定义拆分。
set 本身不保证顺序,但 linkedhashset 保留了插入顺序。如果使用 hashset,@order 可能失效。
解决:声明为 set 时 spring 默认注入 linkedhashset,配合 @order 可以控制顺序。
优先使用自动注入 set。 当需要收集同一接口的所有实现且需要去重时,@autowired set<t> 是最简洁的方式。
用 @order 控制顺序。 当 set 中的元素有执行顺序要求时,给实现类加 @order 注解。
配置文件中的 set 用 @configurationproperties。 比 @value 更类型安全,支持嵌套对象。
处理空 set。 在 @postconstruct 中校验关键 set 是否为空,避免业务逻辑出错。
注意 set 的去重特性。 如果多个 bean 的 equals() 判定相同,set 会去重。确认这是否符合业务预期。
选择合适的具体实现。 如果需要排序,声明为 sortedset 或 treeset;如果需要保留插入顺序,使用默认的 linkedhashset。
| 维度 | 核心要点 |
|---|---|
| xml 注入 | 使用 <set> 标签,支持嵌套、对象、基本类型 |
| @value 注入 | 逗号分隔字符串自动拆分,或使用 spel |
| @configurationproperties | 原生支持复杂 set 绑定,推荐用于配置文件 |
| 自动注入 bean set | 注入容器中所有同类型 bean,自动去重 |
| 默认实现 | linkedhashset(保留插入顺序) |
| 顺序控制 | @order 注解配合 linkedhashset |
| 空 set 处理 | 默认注入空集合,需要时用 @postconstruct 校验 |
| set vs list | set 去重,list 允许重复;set 顺序取决于实现,list 天然有序 |
| 最佳实践 | 自动注入用 set,配置绑定用 @configurationproperties,需要排序用 sortedset |
set 注入是 spring 集合注入的重要形式,特别适合需要去重的多实现场景。理解 set 与 list 的区别、默认实现类的选择以及 @order 的配合,能让你在业务开发中更准确地选择集合类型,写出更符合语义的代码。
以上就是在spring中注入set集合的方法详解的详细内容,更多关于spring注入set集合的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论