Spring util 命名空间详解
一、util 命名空间是什么?
util 命名空间是 Spring 提供的一个 XML 扩展命名空间,专门用于定义集合类型的 Bean。它解决了标准 XML 配置中集合无法独立定义、无法被多个 Bean 复用的问题。
在没有 util 命名空间时,集合只能内联在某个 Bean 的 <property> 中:
xml
<bean id="userService" class="com.example.UserService">
<property name="servers">
<list>
<value>server1</value>
<value>server2</value>
</list>
</property>
</bean>
这个 List 只属于 userService,其他 Bean 无法引用它。如果多个 Bean 需要同一个集合,只能重复配置。
util 命名空间允许把集合定义成独立的 Bean,赋予 id,然后通过 ref 注入到任意 Bean 中。
xml
<util:list id="serverList">
<value>server1</value>
<value>server2</value>
</util:list>
<bean id="userService" class="com.example.UserService">
<property name="servers" ref="serverList"/>
</bean>
<bean id="orderService" class="com.example.OrderService">
<property name="servers" ref="serverList"/>
</bean>
serverList 成为一个独立的 Bean,可以被多个 Bean 共享。
二、引入 util 命名空间
在 XML 根元素中声明:
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- util 标签在这里使用 -->
</beans>
关键是 xmlns:util 和 spring-util.xsd 两行。没有它们,<util:list> 等标签不会被解析。
三、常用标签详解
3.1 <util:list> 定义 List Bean
xml
<util:list id="serverList" list-class="java.util.ArrayList">
<value>server1</value>
<value>server2</value>
<value>server3</value>
</util:list>
list-class 可选,默认是 ArrayList。如果需要 LinkedList,可以指定:
xml
<util:list id="serverList" list-class="java.util.LinkedList">
List 中可以放简单值、Bean 引用、嵌套集合。
xml
<util:list id="mixedList">
<value>text</value>
<ref bean="userDao"/>
<bean class="com.example.User"/>
</util:list>
3.2 <util:set> 定义 Set Bean
xml
<util:set id="serverSet" set-class="java.util.LinkedHashSet">
<value>server1</value>
<value>server2</value>
<value>server1</value> <!-- 自动去重 -->
</util:set>
set-class 可选,默认是 LinkedHashSet。Set 会自动去重,元素顺序取决于实现类。
3.3 <util:map> 定义 Map Bean
xml
<util:map id="configMap" map-class="java.util.LinkedHashMap">
<entry key="timeout" value="30"/>
<entry key="retry" value="3"/>
<entry key="debug" value="true"/>
</util:map>
map-class 可选,默认是 LinkedHashMap。entry 的 key 和 value 可以是简单值、Bean 引用、嵌套对象。
xml
<util:map id="beanMap">
<entry key="primary" value-ref="primaryDataSource"/>
<entry key="secondary" value-ref="secondaryDataSource"/>
</util:map>
3.4 <util:properties> 定义 Properties Bean
方式一:从外部文件加载
xml
<util:properties id="dbProps" location="classpath:db.properties"/>
方式二:内联定义
xml
<util:properties id="appProps">
<prop key="app.name">myapp</prop>
<prop key="app.timeout">30</prop>
</util:properties>
<util:properties> 返回的是 java.util.Properties 对象,键和值都是 String。
3.5 <util:constant> 引用静态常量
xml
<util:constant id="maxValue" static-field="java.lang.Integer.MAX_VALUE"/>
<util:constant id="charset" static-field="java.nio.charset.StandardCharsets.UTF_8"/>
static-field 写全限定类名加字段名。常用于把某个静态常量注册为 Bean。
3.6 <util:property-path> 引用其他 Bean 的属性
xml
<bean id="user" class="com.example.User">
<property name="name" value="张三"/>
</bean>
<util:property-path id="userName" path="user.name"/>
userName 成为一个 Bean,值是 user 的 name 属性。常用于把某个 Bean 的属性暴露为独立的 Bean。
四、与标准集合标签的区别
| 对比维度 | util 命名空间 | 标准 <list>、<map> |
|---|---|---|
| 是否独立 Bean | 是,有 id | 否,内联在属性中 |
| 是否可复用 | 可被多个 Bean 引用 | 只属于当前 Bean |
| 是否可单独获取 | 可以,getBean("id") |
不可以 |
| 定义位置 | 直接放在 <beans> 下 |
嵌套在 <property> 或 <constructor-arg> 中 |
| 适用场景 | 多个 Bean 共享集合 | 单个 Bean 的私有集合 |
五、与 p 命名空间配合
p 命名空间不能直接定义集合,但可以引用 util 定义的集合 Bean。
xml
<util:list id="serverList">
<value>server1</value>
<value>server2</value>
</util:list>
<bean id="userService" class="com.example.UserService"
p:servers-ref="serverList"
p:appName="myapp"/>
这种组合在 XML 配置时代很常见:util 负责定义集合,p 负责注入。
六、底层原理
util 命名空间的解析由 UtilNamespaceHandler 完成,它注册了以下 BeanDefinitionParser:
| 标签 | 解析器 |
|---|---|
<util:list> |
ListBeanDefinitionParser |
<util:set> |
SetBeanDefinitionParser |
<util:map> |
MapBeanDefinitionParser |
<util:properties> |
PropertiesBeanDefinitionParser |
<util:constant> |
ConstantBeanDefinitionParser |
<util:property-path> |
PropertyPathBeanDefinitionParser |
以 <util:list> 为例,解析器会创建一个 ListFactoryBean 的 BeanDefinition,把 list-class、value、ref 等配置转换为 ListFactoryBean 的属性。容器实例化时,ListFactoryBean 的 getObject() 返回实际的 List 对象。
所以 util 定义的集合本质上是工厂 Bean 生产的产品,而不是直接注册的集合对象。
七、完整示例
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="serverList" list-class="java.util.ArrayList">
<value>server1.example.com</value>
<value>server2.example.com</value>
<value>server3.example.com</value>
</util:list>
<util:set id="roleSet">
<value>admin</value>
<value>user</value>
<value>admin</value>
</util:set>
<util:map id="configMap">
<entry key="timeout" value="30"/>
<entry key="retry" value="3"/>
</util:map>
<util:properties id="appProps">
<prop key="app.name">myapp</prop>
<prop key="app.version">1.0</prop>
</util:properties>
<bean id="userService" class="com.example.UserService"
p:servers-ref="serverList"
p:roles-ref="roleSet"
p:configs-ref="configMap"
p:props-ref="appProps"/>
</beans>
Java 类:
java
public class UserService {
private List<String> servers;
private Set<String> roles;
private Map<String, String> configs;
private Properties props;
// setter 方法
public void setServers(List<String> servers) { this.servers = servers; }
public void setRoles(Set<String> roles) { this.roles = roles; }
public void setConfigs(Map<String, String> configs) { this.configs = configs; }
public void setProps(Properties props) { this.props = props; }
}
八、注意事项
1. 需要声明 util 命名空间和 schemaLocation
缺少 xmlns:util 或 spring-util.xsd,标签不会被解析。
2. id 必须唯一
util 定义的集合是独立 Bean,id 不能与其他 Bean 重复。
3. 集合元素类型
<value> 默认是 String,Spring 会尝试类型转换。如果集合是 List<Integer>,Spring 会自动把 "30" 转成 30。
4. <util:properties> 的 location
加载外部文件时,路径要写对:classpath:db.properties 或 file:/opt/config/db.properties。
5. 不支持数组
util 命名空间没有 <util:array>。需要数组时,用 <util:list> 定义 List,注入到数组类型的属性时 Spring 会自动转换。
6. 现代项目中使用减少
Spring Boot 以 Java 配置和注解为主,util 命名空间主要出现在老项目和传统 XML 配置中。理解它有助于维护旧代码。
九、总结
| 维度 | 核心要点 |
|---|---|
| 作用 | 定义独立、可复用的集合 Bean |
| 引入 | xmlns:util + spring-util.xsd |
| 常用标签 | <util:list>、<util:set>、<util:map>、<util:properties>、<util:constant>、<util:property-path> |
| 与标准集合区别 | util 定义的集合是独立 Bean,可被多个 Bean 引用 |
| 与 p 命名空间配合 | util 定义集合,p 负责注入 |
| 底层 | UtilNamespaceHandler + 各标签的 BeanDefinitionParser,本质是工厂 Bean |
| 适用场景 | 多个 Bean 共享集合、需要单独获取集合 Bean、加载 Properties 文件 |
| 注意事项 | 需要命名空间声明、id 唯一、不支持数组、现代项目使用减少 |
util 命名空间是 Spring XML 配置时代管理集合 Bean 的标准工具。它让集合从"某个 Bean 的私有属性"变成"容器中可共享的资源",在需要多个 Bean 共用同一组配置或集合时非常有用。虽然在新项目中已经很少直接使用,但阅读和维护老项目时,掌握 util 命名空间能帮你快速理解配置结构。