从 new 到容器:后端项目依赖注入的六个落地要点
在后端项目里,最常见的坏味道之一是业务类里到处 new:Service 里 new Dao,Dao 里 new 数据源,单测时想换一个 Mock 实现,却发现构造链条牵一发而动全身。依赖注入(Dependency Injection,DI)解决的正是这个问题:把“创建依赖”的权力从业务类手里反转出去,交给外部容器。本文总结六个落地要点。
一、反转的是“创建权”,不是“依赖关系”
依赖关系依然存在——OrderService 依然需要 PaymentGateway。反转的是谁来创建这个 PaymentGateway。业务类只声明“我需要一个 PaymentGateway”,容器在运行时把具体实现装配进来,业务类永远不自己 new。
二、面向接口是前提
// 依赖抽象,而不是具体类
public class OrderService {
private final PaymentGateway paymentGateway;
public OrderService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}
如果 OrderService 直接依赖某个具体支付网关类,就永远失去了替换的可能。接口是 DI 能够成立的前提。
三、三种注入方式,默认用构造器注入
- 构造器注入:依赖不可变、必填,对象创建即完整,最利于测试,推荐默认使用。
- Setter 注入:适合可选依赖,但对象可能处于“半初始化”状态。
- 字段注入 / 接口注入:隐藏了依赖关系,测试困难,不推荐。
Spring 中的典型写法:
@Service
public class OrderService {
private final PaymentGateway paymentGateway;
// 单个构造器时 @Autowired 可省略
public OrderService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}
四、手写一个极简容器,理解 DI 原理
框架做的事情并不神秘,一个极简容器只需“注册表 + 装配”:
public class MiniContainer {
private final Map<Class<?>, Object> singletons = new HashMap<>();
public <T> void register(Class<T> type, T instance) {
singletons.put(type, instance);
}
@SuppressWarnings("unchecked")
public <T> T resolve(Class<T> type) {
return (T) singletons.get(type);
}
}
// 使用:组装逻辑集中在容器,业务类只管声明
MiniContainer container = new MiniContainer();
container.register(PaymentGateway.class, new AlipayGateway());
OrderService service = new OrderService(container.resolve(PaymentGateway.class));
Spring、Guice 等框架本质相同,只是多了扫描注册、按依赖图自动装配、管理生命周期等能力。
五、生命周期交给容器
- 单例(singleton):默认,无状态服务共享一个实例;
- 原型(prototype):每次获取都新建实例;
- 请求作用域:Web 场景下每个请求一个实例。
业务代码不再操心何时创建、何时销毁,避免资源浪费和状态错乱。
六、循环依赖:优先重构,延迟注入兜底
A 依赖 B、B 又依赖 A,通常是职责划分不清的信号。优先重构拆分;实在拆不开,再用 Setter 注入或 @Lazy 延迟注入兜底,不要把循环依赖当常态。
结语:测试是检验标准
DI 是否落地成功,看测试就知道。因为依赖都通过构造器传入,单测只需一行:
OrderService service = new OrderService(new MockPaymentGateway());
无需启动整个容器。落地检查清单:
- [ ] 业务类只依赖接口 / 抽象
- [ ] 优先使用构造器注入
- [ ] 容器统一装配,业务代码不直接 new 依赖
- [ ] 单例为默认,明确需要时才用原型或请求作用域
- [ ] 出现循环依赖先重构
一句话总结:接口隔离依赖 + 构造器注入声明依赖 + 容器统一装配 = 低耦合、易测试的后端项目。
- 点赞
- 收藏
- 关注作者
评论(0)