Spring 构造器注入 vs 字段注入

一、核心结论(先背这个)

Spring 推荐构造器注入,而不推荐字段注入,
是因为构造器注入能保证对象在创建完成时依赖已经全部就绪,
而字段注入会让对象在一段时间内处于"不完整状态"。


二、两种注入方式的本质区别

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

java 复制代码
@Service
public class OrderService {

    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }
}

本质:

  • 依赖作为构造器参数
  • 没有依赖就无法创建对象
  • 依赖在 new 之前就必须准备好

创建顺序(类比"深度优先"):

text 复制代码
创建 A
 → 先创建 B
   → 再创建 C
 → 再创建 A

2️⃣ 字段注入(Field Injection)

java 复制代码
@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;
}

本质:

  • 先 new 一个"空壳对象"
  • 再通过反射把依赖"塞进去"

创建顺序:

text 复制代码
new OrderService()   ← 依赖此时是 null
↓
反射注入 orderRepository

三、字段注入真实会出错的原因

❌ 出错根源(不是 Spring 的问题)

对象在依赖注入完成之前就已经存在,并且可能被使用


❌ 典型错误示例

java 复制代码
@Service
public class ReportService {

    @Autowired
    private UserRepository userRepository;

    public ReportService() {
        // 此时 userRepository 还没注入
        userRepository.findAll(); // 💥 NPE
    }
}

原因:

  • 构造器执行时,字段注入尚未发生
  • 依赖是 null

✅ 构造器注入不会有这个问题

java 复制代码
public ReportService(UserRepository userRepository) {
    this.userRepository = userRepository;
    userRepository.findAll(); // 一定安全
}

四、设计层面的差异(面试加分点)

字段注入的问题

  • 依赖关系 隐藏
  • 无法使用 final
  • 不利于单元测试
  • 容易掩盖设计问题(依赖过多)

构造器注入的优势

  • 依赖关系 一眼可见
  • 支持 final(不可变)
  • 创建即完整
  • 更容易测试
  • 循环依赖会更早暴露

五、你提出的"深度优先"理解(标准化表述)

构造器注入在 Bean 创建阶段会先解析并实例化其构造器参数,

形成一种类似 深度优先 的依赖构建过程,

从而保证对象在创建完成后依赖已经全部注入完成。

而字段注入是在对象实例化之后再进行依赖填充,

对象在此期间可能处于不完整状态。


六、30 秒面试速记版(终极版)

构造器注入是在对象创建时通过构造方法一次性注入依赖,

可以保证对象创建完成后就是可用状态;

字段注入是先创建对象再通过反射注入依赖,

对象可能短暂处于不完整状态,因此 Spring 官方更推荐构造器注入。

相关推荐
RAG学徒loading10 分钟前
我把 RAG 召回从 57.6% 做到 78.8%,然后发现 75% 的真实问题它答不了
后端
用户425693999962010 分钟前
我的 HashMap 查找全废了,但 36 个测试全绿
后端
小番茄程序猿16 分钟前
Redis 编码压测 59 轮:HSET 快 23 倍是假象,SMEMBERS 慢 30 倍是真的
redis·后端
Moment1 小时前
代码都能让 Agent 写了,我们为什么还要学前端?
前端·后端·面试
aiks_yuan1 小时前
Java CPU 100% 怎么排查:JDK 11 起 jstack 自带线程 CPU 时间,不用再 top -H 换算十六进制(JDK 8、11、17 实测)
java
AI入职记1 小时前
Spring AI 实测:不挂工具,模型真的会瞎编吗?
后端·ai编程
wei_shuo1 小时前
SQL Server数据迁移实战:内置故障诊断工具与根因分析实践
后端
一条Go1 小时前
告警指纹:一次故障为什么只产生一条 FIRING 记录
后端·架构·github
鶴哥只手遮天1 小时前
《Redis 8.10.3 深度剖析》系列 ·第 13 章 Set:三种编码、集合运算与随机采样
redis·后端·开源