Skip to content

不同依赖注入方式有哪些及其区别

在 Spring 中,依赖注入(Dependency Injection, DI)是实现控制反转(IOC)的核心方式,主要有三种注入方式:构造器注入Setter 注入字段注入。它们通过不同途径将依赖注入到 Bean 中,区别在于注入位置、代码风格、可读性和适用场景。


1. 不同依赖注入方式

(1) 构造器注入(Constructor Injection)

  • 定义:通过构造器参数注入依赖。
  • 实现
  • 使用 @Autowired 或显式构造器。
  • 代码
@Component
public class UserService {
    private final UserDao userDao;

    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}

(2) Setter 注入(Setter Injection)

  • 定义:通过 Setter 方法注入依赖。
  • 实现
  • 使用 @Autowired 标注 Setter。
  • 代码
@Component
public class UserService {
    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

(3) 字段注入(Field Injection)

  • 定义:直接在字段上使用注解注入依赖。
  • 实现
  • 使用 @Autowired@Resource
  • 代码
@Component
public class UserService {
    @Autowired
    private UserDao userDao;
}

其他(补充)

  • 接口注入(较少使用):
  • 通过接口定义注入方法,Spring 不直接支持。
  • XML 配置注入
  • 通过 <constructor-arg><property> 配置(老式方式)。

2. 区别

维度 构造器注入 Setter 注入 字段注入
注入位置 构造器参数 Setter 方法 字段直接
依赖声明 强制(构造时注入) 可选(可不调用 Setter) 可选(反射注入)
不可变性 支持(final 字段) 不支持(可多次设置) 不支持(可反射修改)
代码可读性 明确(构造器显式) 中等(需找 Setter) 简洁(但隐藏依赖)
测试性 强(手动构造传入) 中等(需调用 Setter) 弱(依赖反射)
Spring 默认 @Autowired 可省略(唯一构造器) 需显式标注 需显式标注
适用场景 核心依赖 可选依赖 简单场景(不推荐)

详细对比

  1. 依赖强弱
  2. 构造器:强制依赖,Bean 创建时必须注入。
  3. Setter:可选依赖,可运行时动态调整。
  4. 字段:隐式依赖,不强制。

  5. 不可变性

  6. 构造器:支持 final,防止修改。
  7. Setter/字段:可变,存在风险。

  8. 代码风格

  9. 构造器:符合“依赖显式声明”原则。
  10. Setter:传统风格,灵活但冗长。
  11. 字段:简洁但隐藏依赖关系。

  12. 异常处理

  13. 构造器:依赖缺失,启动失败(早期发现)。
  14. Setter/字段:运行时才暴露问题。

3. 示例(综合)

@Component
public class UserService {
    private final UserDao userDao; // 构造器注入
    private Logger logger;         // Setter 注入
    @Autowired
    private Config config;         // 字段注入

    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Autowired
    public void setLogger(Logger logger) {
        this.logger = logger;
    }
}

4. 优缺点与选择

构造器注入

  • 优点
  • 依赖明确,初始化即完成。
  • 支持不可变对象(final)。
  • 测试友好(手动构造)。
  • 缺点
  • 构造器参数多时代码冗长。
  • 场景:核心依赖,必选依赖。

Setter 注入

  • 优点
  • 灵活,可选依赖动态调整。
  • 支持循环依赖(Spring 允许)。
  • 缺点
  • 不可变性差,运行时可变。
  • 依赖不直观。
  • 场景:可选依赖,配置变更。

字段注入

  • 优点
  • 代码简洁,编写快。
  • 缺点
  • 隐藏依赖,测试困难(需反射)。
  • 不可变性差,社区不推荐。
  • 场景:简单原型,快速开发(生产慎用)。

延伸与面试角度

  • Spring 演进
  • 4.0+ 默认支持构造器注入(唯一构造器可省 @Autowired)。
  • 循环依赖
  • 构造器:无法解决,启动报错。
  • Setter/字段:Spring 通过代理解决。
  • 最佳实践
  • 优先构造器注入,Setter 辅助,尽量避免字段注入。
  • 面试点
  • 问“区别”时,提不可变性和测试。
  • 问“选择”时,提场景和 Spring 推荐。

总结

Spring DI 包括构造器、Setter 和字段注入,区别在注入方式、依赖性、可读性和场景。构造器注入最优,Setter 灵活,字段简洁但不推荐。面试时,可写示例或提循环依赖,展示理解深度。