Spring MVC 什么是现场注入以及如何避免它?

ycggw6v2  于 2023-05-29  发布在  Spring
关注(0)|答案(5)|浏览(192)

我在一些关于Spring MVC和Portlet的帖子中读到,不推荐 * 字段注入 *。正如我所理解的,field injection 是当你像这样用@Autowired注入Bean时:

@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:**由于此问题被标记为this question的重复,我检查了它。因为在问题和答案中都没有任何代码示例,所以我不清楚我对我使用的注入类型的猜测是否正确。

xxslljrj

xxslljrj1#

注射类型

有三种方法可以将依赖项注入到bean中:
1.通过构造函数
1.通过setter或其他方法
1.通过反射,直接进入田地
您正在使用选项3。这就是当您直接在您的领域使用@Autowired时所发生的情况。

注射指南

一个通用的指导原则which is recommended by Spring(参见基于构造器的DI或基于设置器的DI部分)如下所示:

  • 对于强制依赖项或当目标是不可变性时,使用构造函数注入
  • 对于可选的或可变的依赖项,使用setter注入
  • 在大多数情况下避免现场注入
    现场注入缺点

不赞成现场注入的原因如下:

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

根据您的需要,您应该主要使用构造函数注入或构造函数和setter注入的混合。现场注入有许多缺点,应该避免。字段注入的唯一优点是它更便于编写,这并不超过所有的缺点。

进一步阅读

我写了一篇关于为什么通常不推荐现场注入的博客文章:Field Dependency Injection Considered Harmful

bjp0bcyl

bjp0bcyl2#

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

构造函数注入

优点:

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

缺点:

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

基本上,场注入相反。

cl25kdpy

cl25kdpy3#

品味问题。这是你的决定。
但是我可以解释,为什么我从来不使用 * 构造函数注入 *。
1.我不想为所有@Service@Repository@Controller bean实现构造函数。我的意思是,有大约40-50个豆子或更多。每次我添加一个新的字段,我都必须扩展构造函数。不我不想也没必要
1.如果您的Bean(服务或控制器)需要注入许多其他Bean,该怎么办?一个有4个以上参数的构造函数是非常丑陋的。
1.如果我使用的是CDI,那么构造函数与我无关。

编辑#1:Vojtech Ruzicka说:

类有太多的依赖项,可能违反了单一责任原则,应该重构
是的理论和现实下面是一个例子:DashboardControllerMap到单路径*:8080/dashboard
我的DashboardController从其他服务收集了大量信息,并将其显示在 Jmeter 板/系统概述页面中。我需要这个控制器。所以我必须只保护这一条路径(基本身份验证或用户角色过滤器)。

编辑#2:由于每个人都关注构造函数中的8个参数...这是一个真实的示例-客户遗留代码。我已经改变了同样的论证也适用于我的4+参数。

这都是关于代码注入,而不是示例构造。

bz4sfanl

bz4sfanl4#

另一条评论- Vojtech Ruzicka表示Spring以三种方式注入bean(得分最多的答案):
1.通过构造函数
1.通过setter或其他方法
1.通过反射,直接进入田地
这个答案是错误的-因为每一种注射Spring都使用反射!使用IDE,在setter / constructor上设置断点,并检查。
这可能是一个品味的问题,但也可能是一个案例的问题。@dieter提供了一个极好的情况下,现场注入更好。如果您在设置Spring上下文的集成测试中使用字段注入-类的可测试性参数也是无效的-除非您想稍后将测试写入您的集成测试;)

velaa5lx

velaa5lx5#

我知道这是7年后的事了,但要补充Vojtech Ruzicka的回复- @Autowired on fields不会对单元测试造成问题,考虑到Mockitos @InjectMocks注解。

相关问题