Spring集合注入默认生成可变集合,不可变性需开发者手动封装(如Collections.unmodifiableList或List.copyOf),XML配置不支持自动不可变,推荐构造注入+final字段保障不可变语义。
Java 中 Collections 工具类本身不直接参与 Spring 的 Bean 属性注入,也不能用于创建「Spring 可识别的不可变集合」来完成属性注入。真正起作用的是 Spring 容器对集合类型(List、Set、Map)的 XML 或注解配置支持,而不可变性需由开发者主动保障——Collections.unmodifiableXXX() 是运行时防护手段,不是注入机制的一部分。
Spring 在解析 <list>、<set>、<map> 等标签时,底层默认创建的是标准可变集合(如 ArrayList、LinkedHashSet、LinkedHashMap)。即使你写:
<list><value>a</value><value>b</value></list>ArrayList,而非 Collections.unmodifiableList(...)
这意味着:注入后若业务代码调用 list.add(...),不会报错——它确实是可变的。
若需注入后即不可修改,应在 Bean 初始化阶段完成封装。常见做法有两种:
立即学习“Java免费学习笔记(深入)”;
public void setRoles(List<String> roles) { this.roles = Collections.unmodifiableList(new ArrayList<>(roles)); }
public UserService(List<String> permissions) { this.permissions = Collections.unmodifiableList(permissions); } 注意:此时需确保传入的 permissions 是副本(避免外部仍持有原始引用),否则仍可能被间接修改。Spring 的 XML 集合标签(<list> 等)不提供 immutable="true" 这类属性,也不支持调用 Collections.unmodifiableList() 这样的静态工厂方法。它只负责实例化和填充集合,不干预其运行时行为。
试图在 XML 中这样写是无效的:
<property name="items"><bean class="java.util.Collections" factory-method="unmodifiableList"><constructor-arg><list>...</list></constructor-arg></bean></property> —— 这不是标准用法,Spring 不识别此类嵌套工厂调用(除非自定义 FactoryBean)在 Spring Boot + Java 14+ 场景下,更自然的方式是:
@AllArgsConstructor 或显式构造函数接收集合参数final,并在构造中赋值并封装:this.roles = List.copyOf(roles);(Java 10+)或 Collections.unmodifiableList(...)
@Builder 或 Record 类进一步强化不可变契约例如:
public record Config(List<String> endpoints) {不复杂但容易忽略:不可变性不是配置出来的,而是设计出来的。Spring 注入的是“数据”,而“是否可变”取决于你如何持有和暴露它。