5. Spring DI 依赖注入(构造器、Setter)
核心概念
Spring 依赖注入(DI)是 IoC 核心实现,核心分为构造器注入(推荐)和Setter 注入两种方式,以下从「XML 配置」「注解配置」双维度整理,兼顾传统写法与主流语法糖
构造器注入(Constructor Injection)
核心思想
通过类的构造方法传入依赖对象,Spring 容器创建 Bean 时调用构造方法完成注入
- ✅ 优点:确保依赖非空,Bean 创建后即完整;适合必选核心依赖(如 Service/Repository)
- ❌ 缺点:无法解决循环依赖;多参数时配置稍繁琐
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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 1. 定义被依赖的 Bean --> <bean id="userService" class="com.example.service.impl.UserServiceImpl"/> <!-- 2. 构造器注入 UserController --> <bean id="userController" class="com.example.controller.UserController"> <!-- 方式1:按参数索引(不推荐,参数顺序变易出错) --> <constructor-arg index="0" ref="userService"/> <!-- 方式2:按参数类型(推荐,精准匹配) --> <!-- <constructor-arg type="com.example.service.UserService" ref="userService"/> --> <!-- 方式3:按参数名称(推荐,最直观) --> <!-- <constructor-arg name="userService" ref="userService"/> --> <!-- 扩展:注入基本类型参数 --> <!-- <constructor-arg name="version" value="1.0.0"/> --> </bean> </beans>核心语法
| 标签属性 | 作用 | 示例 |
|---|---|---|
index | 构造方法参数索引(从 0 开始) | index="0" |
type | 构造方法参数全类名 | type="com.example.service.UserService" |
name | 构造方法参数名称 | name="userService" |
ref | 引用容器中已定义的 Bean(对象类型) | ref="userService" |
value | 注入基本类型 / 字符串 | value="1.0.0" |
注解配置方式(主流语法糖)
基础写法(无 Lombok)
// 1. 被依赖的 Service(@Service 声明为 Bean) package com.example.service.impl; import com.example.service.UserService; import org.springframework.stereotype.Service; @Service // Bean 名称默认:userServiceImpl public class UserServiceImpl implements UserService {} // 2. 控制器类(构造器注入) package com.example.controller; import com.example.service.UserService; import org.springframework.stereotype.Controller; @Controller public class UserController { // 必选依赖建议用 final 修饰 private final UserService userService; // 语法糖:单个构造方法 → 无需加 @Autowired public UserController(UserService userService) { this.userService = userService; } // 多构造方法时 → 显式加 @Autowired 指定注入的构造器 // @Autowired // public UserController(UserService userService, String version) { // this.userService = userService; // } }简化写法(Lombok 语法糖)
package com.example.controller; import com.example.service.UserService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; @Controller @RequiredArgsConstructor // 自动生成 final 变量的构造器,替代手动编写 public class UserController { private final UserService userService; // 自动注入 }Setter 注入(Setter Injection)
核心思想
通过类的setXxx()方法传入依赖对象,Spring 先创建 Bean 实例,再调用 Setter 方法完成注入
- ✅ 优点:支持可选依赖,可动态修改;能解决循环依赖(Spring 三级缓存)
- ❌ 缺点: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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 1. 定义被依赖的 Bean --> <bean id="userService" class="com.example.service.impl.UserServiceImpl"/> <!-- 2. Setter 注入 UserController --> <bean id="userController" class="com.example.controller.UserController"> <!-- 注入对象类型:name 对应 Setter 方法名(setUserService → userService) --> <property name="userService" ref="userService"/> <!-- 注入基本类型:直接赋值 --> <property name="version" value="1.0.0"/> </bean> </beans>核心语法
| 标签属性 | 作用 | 示例 |
|---|---|---|
name | 对应 Setter 方法名(去掉 set 前缀,首字母小写) | name="userService" |
ref | 引用容器中已定义的 Bean(对象类型) | ref="userService" |
value | 注入基本类型 / 字符串 | value="1.0.0" |
注解配置方式(主流语法糖)
package com.example.controller; import com.example.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import javax.annotation.Resource; @Controller public class UserController { // 语法糖1:@Autowired 直接加在成员变量(跳过 Setter 方法) @Autowired // 多同类型 Bean 时,用 @Qualifier 指定名称 @Qualifier("userServiceImpl") private UserService userService; // 语法糖2:@Resource(JDK 注解,按名称注入) // @Resource(name = "userService") // private UserService userService; // 传统写法:@Autowired 加在 Setter 方法 // public void setUserService(UserService userService) { // this.userService = userService; // } }两种注入方式对比
| 特性 | 构造器注入 | Setter 注入 |
|---|---|---|
| 依赖必要性 | 必选(构造时必须传入) | 可选(可后续设置) |
| Bean 完整性 | 创建后即完整 | 初始化后可能缺依赖 |
| 循环依赖 | 无法解决 | 可解决(Spring 三级缓存) |
| 推荐场景 | 核心必选依赖(Service/Repository) | 可选依赖(配置参数 / 工具类) |
| XML 核心标签 | <constructor-arg> | <property> |
| 注解核心语法糖 | @RequiredArgsConstructor | @Autowired/@Resource |
关键注意事项
- 注解注入时,
@Autowired先按类型匹配,再按名称;@Resource先按名称匹配,再按类型 - XML 配置中,Bean 的
id必须唯一,class属性需写完整包名 + 类名 - 实际开发优先用构造器注入管理核心依赖,Setter 注入仅用于可选依赖
总结
- Spring DI 核心为构造器注入(必选依赖)和 Setter 注入(可选依赖),均支持 XML 纯配置、注解两种实现方式
- 构造器注入推荐用注解 + Lombok(
@RequiredArgsConstructor),XML 中优先用type/name匹配参数 - Setter 注入注解版可直接在成员变量加
@Autowired/@Resource,XML 中通过<property>匹配 Setter 方法名
