tl; dr-构造函数注入是执行DI的最佳方法
后者是正确的,并不是因为Spring或任何依赖注入容器,而是面向对象的类设计原则。
细节
应该设计一种类型,以便您只能根据其创建处于有效状态的实例。为了实现这一目标,该类型的所有强制依赖 的需要
是构造函数的参数。这意味着,可以
null检查这些依赖项,并将其分配给最终字段以促进不变性。除此之外,在处理代码时,对于该实例的调用者(或创建者),可以立即看出它必须提供哪些依赖项(通过浏览API文档或在IDE中使用代码完成功能)。
使用场注入无法实现所有这些功能。您不会从外部看到依赖关系, 需要使用
一些黑魔法来注入依赖关系,并且
null除非您盲目地信任容器,否则您永远无法确保它们不是。
最后但并非最不重要的一个方面实际上是,使用字段注入,为类添加许多依赖关系会比较容易,这本身就是设计问题。对于构造函数来说,它在更早的时候就变得更加痛苦,这是
一件好事, 因为它告诉您有关类设计的一些信息:类承担太多的责任。首先无需计算指标,当您尝试扩展它时会感觉到。
货柜
人们经常争辩说,这只是学术废话,因为无论如何您都可以依赖容器。这是我的看法:
仅仅因为容器存在,并不意味着您必须将所有基本的面向对象的设计原则都抛在脑后,对吗?即使有止汗剂,您仍然要洗个澡,对吗?
即使是设计用于容器的类型, 也将 手动使用:在单元测试中。如果您不编写单元测试,那么这是另一个主题。
可以减轻所谓的附加构造函数的冗长性(“我可以用单行注入实现相同的功能!!”-“不,您不能。实际上您可以通过编写更多的代码来 获得 一些东西。”)通过龙目岛(Lombok)之类的东西。使用Spring和Lombok注入构造函数的组件如下所示:
@Component
@RequiredArgsConstructor
class MyComponent implements MyComponentInterface {private final @NonNull MyDependency dependency;
…
}
Lombok将负责生成一个构造函数,该构造函数为每个final字段采用一个参数,并
null在分配给定参数之前检查给定参数。因此,您可以有效地获得现场注入的简短性和构造函数注入的设计优势。
结语
最近,我参加了与一些非Java人士的讨论,我对构造函数DI使用“注入”一词感到非常困惑。实际上,他们认为-这样做有很多道理-
通过构造函数传递依赖项根本不是注入,因为这是将对象传递给其他对象的最自然的方式(与各种注入形成鲜明对比)。
也许我们应该为这种风格创造一个不同的术语?依赖喂食,也许吗?
资源资源
- 奥利弗·吉尔克(Oliver Gierke)-为什么电场注入是邪恶的
- Jens Schauder-做依赖注入的一种正确方法



