究竟什么是现场注入以及如何避免它?

我在一些关于Spring MVC和Portlets的帖子中读到,不建议进行现场注入。据我所知,现场注入是当你用这样的方式注入一个Bean时:@Autowired

@Component
public class MyComponent {
    @Autowired
    private Cart cart;
}

在我的研究过程中,我还读到了关于构造函数注入的信息:

@Component
public class MyComponent {
    private final Cart cart;

    @Autowired
    public MyComponent(Cart cart){
       this.cart = cart;
    }
}

这两种类型的注射的优点和缺点是什么?


编辑1:由于这个问题被标记为与这个问题重复,我检查了它。因为在问题和答案中都没有任何代码示例,我不清楚我是否猜对了我正在使用的注入类型。


答案 1

注射类型

对于如何将依赖关系注入到 Bean 中,有三个选项:

  1. 通过构造函数
  2. 通过设置器或其他方法
  3. 通过反射,直接进入现场

您正在使用选项 3。这就是你直接在球场上使用时发生的事情。@Autowired


注射指南

Spring推荐的一般准则(请参阅基于构造函数的DI基于Setter的DI部分)如下:

  • 对于强制依赖项或旨在实现不可变性时,请使用构造函数注入
  • 对于可选或可更改的依赖项,请使用 setter 注入
  • 在大多数情况下避免现场注射

现场注入的缺点

现场注射不受欢迎的原因如下:

  • 不能像使用构造函数注入那样创建不可变对象
  • 您的类与 DI 容器紧密耦合,不能在它之外使用
  • 如果没有反射,就无法实例化类(例如在单元测试中)。您需要 DI 容器来实例化它们,这使您的测试更像集成测试
  • 您的实际依赖项在外部隐藏,并且不会反映在接口(构造函数或方法)中
  • 拥有十个依赖关系真的很容易。如果您使用的是构造函数注入,则将有一个具有十个参数的构造函数,这将表明某些内容是可疑的。但是,您可以使用字段注入无限期地添加注入的字段。具有太多的依赖项是一个危险信号,表明该类通常执行多个操作,并且它可能违反单一责任原则。

结论

根据您的需要,您应该主要使用构造函数注入或构造函数和 setter 注入的某种混合。现场注射有许多缺点,应避免。场注入的唯一优点是写起来更方便,不会超过所有的缺点。


进一步阅读

我写了一篇关于为什么通常不建议进行现场注入的博客文章:字段依赖注入被认为是有害的


答案 2

这是软件开发中永无止境的讨论之一,但业内的主要影响者对这个话题越来越固执己见,并开始建议构造函数注入作为更好的选择。

构造函数注入

优点:

  • 更好的可测试性。在单元测试中,您不需要任何模拟库或Spring上下文。您可以创建要使用 new 关键字进行测试的对象。这样的测试总是更快,因为它们不依赖于反射机制。(这个问题在30分钟后被问到。如果作者使用了构造函数注入,它就不会出现)。
  • 不变性。一旦设置了依赖项,就无法更改它们。
  • 更安全的代码。执行构造函数后,您的对象就可以使用了,因为您可以验证作为参数传递的任何内容。对象可以是就绪的,也可以不是,中间没有状态。使用场注入,当对象脆弱时,您将引入中间步骤。
  • 更清楚地表达了强制依赖关系。现场注入在这个问题上是模棱两可的。
  • 让开发人员思考设计。dit写了一个具有8个参数的构造函数,这实际上是一个糟糕的设计和上帝对象反模式的标志。无论一个类在其构造函数中还是在字段中有 8 个依赖项,它总是错误的。人们更不愿意向构造函数添加更多依赖项,而不是通过字段。它向你的大脑发出一个信号,你应该停下来一段时间,想想你的代码结构。

缺点:

  • 更多的代码(但现代IDE减轻了痛苦)。

基本上,现场注入是相反的。


推荐