Spring XML 配置
本章定位 :掌握 Spring IoC 容器的 XML 配置方式——bean 定义、构造器注入、Setter 注入、命名空间扩展(c/p/util/context/aop)。
定义与作用
Spring Framework 虽然现在推荐注解和 Java Config,但 XML 配置是其 最经典 的 Bean 定义方式,也是理解 Spring IoC 原理的最佳切入点。
Spring XML 配置文件的核心作用:声明 Bean("你要管哪些对象")及其依赖关系("谁需要谁")。Spring 容器启动时读取 XML,使用反射创建对象并注入依赖,最终将所有 Bean 放入 ApplicationContext 中统一管理。
即使你主要用注解开发,理解 XML 配置仍然是必要的——很多遗留项目和维护文档中都使用 XML 配置。
核心原理:Spring IoC 容器从 XML 到 Bean
图解释 :Spring 容器通过 XmlBeanDefinitionReader 将 XML 转化为内部的 BeanDefinition 元数据,然后经历实例化→依赖注入→后处理的完整生命周期,最终存放到 ApplicationContext 中。
语法/结构要点
基础 bean 定义
<!-- 最简 Bean -->
<bean id="studentDao" class="com.feixiang.dao.StudentDao"/>
<!-- 通过构造器注入 -->
<bean id="studentService" class="com.feixiang.service.StudentService">
<constructor-arg ref="studentDao"/>
<constructor-arg value="乐途大学"/>
</bean>
<!-- 通过 Setter 注入 -->
<bean id="config" class="com.feixiang.config.AppConfig">
<property name="maxStudents" value="100"/>
<property name="dataSource" ref="dataSource"/>
</bean>
命名空间扩展
| 命名空间 | 前缀 | 典型用途 |
|---|---|---|
util | <util:list> | 定义集合 Bean |
context | <context:component-scan> | 自动扫描 @Component |
p | p:name="value" | 简化 Setter 注入 |
c | c:dao-ref="dao" | 简化构造器注入 |
aop | <aop:config> | AOP 配置 |
完整示例:白歌用 XML 配置教学管理系统
场景说明
飞翔科技的架构师 白歌 为教学管理系统编写 Spring XML 配置。系统包含:数据源、DAO 层、Service 层,使用构造器注入(强制依赖)和 Setter 注入(可选依赖)混合。
applicationContext.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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 启用注解的 Bean 后处理器 -->
<context:annotation-config/>
<!-- 数据源(使用属性占位符) -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/edu"/>
<property name="username" value="root"/>
<property name="password" value="dev123"/>
</bean>
<!-- DAO 层:无依赖 -->
<bean id="studentDao" class="com.feixiang.edu.dao.StudentDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="courseDao" class="com.feixiang.edu.dao.CourseDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Service 层:构造器注入(强制依赖) + Setter 注入(可选) -->
<bean id="studentService"
class="com.feixiang.edu.service.StudentService">
<!-- 构造器注入:studentDao 是必须的 -->
<constructor-arg ref="studentDao"/>
<!-- Setter 注入:可选的最大学生数 -->
<property name="maxEnrollment" value="50"/>
</bean>
<bean id="courseService"
class="com.feixiang.edu.service.CourseService">
<constructor-arg ref="courseDao"/>
<constructor-arg ref="studentDao"/>
</bean>
<!-- 用 util 命名空间定义集合 -->
<util:list id="adminEmails">
<value>baige@learnto.cn</value>
<value>daxiang@learnto.cn</value>
</util:list>
<bean id="notificationService"
class="com.feixiang.edu.service.NotificationService">
<property name="adminEmails" ref="adminEmails"/>
<property name="systemName" value="飞翔科技教学管理系统"/>
</bean>
</beans>
Java 代码
public class StudentService {
private final StudentDao studentDao; // 构造器注入(不可变)
private int maxEnrollment = 30; // Setter 注入(有默认值)
public StudentService(StudentDao studentDao) {
this.studentDao = studentDao; // 必须依赖
}
public void setMaxEnrollment(int maxEnrollment) {
this.maxEnrollment = maxEnrollment; // 可选依赖
}
}
操作结果
Spring 容器启动时:①创建 dataSource Bean → ②注入到 studentDao/courseDao → ③通过构造器将 studentDao 注入 studentService → ④通过 Setter 设置 maxEnrollment=50 → ⑤所有 Bean 就绪。
如果 studentDao 缺失,容器启动就会失败(构造器注入保证了依赖完整性)。
易错场景
错误一:构造器参数顺序错误
<!-- ❌ 多个同类型参数容易搞错顺序 -->
<constructor-arg ref="courseDao"/>
<constructor-arg ref="studentDao"/>
<!-- ✅ 用 index 或 name 明确指定 -->
<constructor-arg index="0" ref="courseDao"/>
<constructor-arg index="1" ref="studentDao"/>
错误二:循环依赖
<bean id="a" class="A">
<constructor-arg ref="b"/>
</bean>
<bean id="b" class="B">
<constructor-arg ref="a"/>
</bean>
构造器注入的循环依赖无法解决(Spring 会抛 BeanCurrentlyInCreationException)。改为 Setter 注入或重构设计。
面试考点
| 考点 | 参考答案要点 |
|---|---|
| Spring XML 配置中构造器注入和 Setter 注入的区别? | 构造器注入:强制依赖、不可变、容器启动即检测缺失;Setter 注入:可选依赖、可变、可能处于不完整状态 |
| Spring Bean 的生命周期阶段? | 实例化→属性填充→BeanNameAware→BeanFactoryAware→BeanPostProcessor.before→InitializingBean→init-method→BeanPostProcessor.after→就绪→DisposableBean→destroy-method |
| XML 中如何注入集合类型? | 用 <list>/<set>/<map>/<props> 或 util 命名空间的 <util:list> 等 |