当前位置: 当前位置:首页 > 综合 > spring注入的三种方式正文

spring注入的三种方式

作者:百科 来源:探索 浏览: 【大 中 小】 发布时间:2026-10-17 06:18:22 评论数:

Spring 把对象塞进字段里,注入最常用的注入就三种方式:构造器注入、setter 注入、注入字段注入。注入但很多人写了好几年,注入依然分不清什么时候该用哪个,注入甚至觉得“能跑就行”。注入我见过一个项目,注入所有依赖都用 @Autowired 标在字段上,注入结果单元测试时反射工具都救不了场,注入最后只能启动整个 Spring 容器——测试跑一轮 40 秒。注入

先看构造器注入。注入它靠的注入是类自己的构造函数,Spring 在创建 bean 时把依赖当参数传进去。注入写法上可以省略 @Autowired,注入只要类里只有一个构造器,Spring 4.3 之后自动识别。举个例子:

@Service public class OrderService {  private final PaymentGateway gateway; public OrderService(PaymentGateway gateway) {  this.gateway = gateway; } }

这种写法最大的好处是依赖不可变——字段加 final,对象一出生依赖就固定了。还有个隐藏福利:如果依赖太多,构造器参数列表会变得很长,这其实是个信号——这个类可能承担了太多职责。我见过一个 8 个参数的构造器,后来拆成了三个类,代码立刻清爽了。Spring 官方也推荐构造器注入,因为它能保证 bean 完全初始化后才被使用,避免循环依赖的隐患。

setter 注入走的是另一条路。Spring 先调用无参构造器创建对象,再通过 setter 方法把依赖设进去。写法长这样:

@Service public class UserService {  private EmailSender emailSender; @Autowired public void setEmailSender(EmailSender emailSender) {  this.emailSender = emailSender; } }

setter 注入适合可选依赖——有些场景下这个依赖可以没有,或者允许在运行时替换。但它的缺点也明显:对象创建后依赖可能还是 null,你得在 setter 里做判空,或者用 @Required 强制校验。我个人的经验是,除非确实需要动态替换,否则别用 setter 注入。它让依赖关系变得不那么确定,读代码时得多跳一步。

字段注入是日常代码里出现频率最高的,因为它写起来最短:

@Service public class ProductService {  @Autowired private InventoryClient inventoryClient; }

一行搞定,不用构造器也不用 setter。但问题也最多。首先,你没法把字段声明成 final,依赖在类外部可以被反射修改。其次,脱离 Spring 容器这个类基本没法用——new 出来之后 inventoryClient 是 null,只能靠反射工具硬塞。更隐蔽的是,字段注入容易让人不自觉地堆依赖。构造器参数多了你会想重构,字段多了却常常视而不见,因为写起来太顺手了。

那到底怎么选?我的判断很简单:强制依赖用构造器,可选依赖用 setter,字段注入尽量别碰。有些团队用 Lombok 的 @RequiredArgsConstructor 配合构造器注入,代码短且安全,算是个折中方案。另外,Spring 团队从 4.3 开始就在文档里明确建议用构造器注入,字段注入更多是历史遗留和便利性的产物。

最后提一个实际踩过的坑:字段注入和构造器注入混用时,如果构造器里调用了依赖的方法,而那个依赖是字段注入的,就会拿到 null。因为构造器执行时字段还没被注入。这种 bug 在启动时不一定报错,运行到特定路径才炸,排查起来很头疼。换成构造器注入,编译期就能发现这类问题。