Java 什么是现场注入,如何避免?

Java 什么是现场注入,如何避免?,java,spring-mvc,dependency-injection,portlet,autowired,Java,Spring Mvc,Dependency Injection,Portlet,Autowired,我在一些关于SpringMVC和Portlet的帖子中读到,不推荐使用字段注入。据我所知,字段注入是指使用@Autowired注入Bean,如下所示: @Component public class MyComponent { @Autowired private Cart cart; } 在我的研究期间,我还阅读了有关构造函数注入的内容: 这两种注射的优点和缺点是什么 编辑1:因为这个问题被标记为重复的,所以我检查了它。因为问题和答案中都没有任何代码示例,我不清楚我的猜测是

我在一些关于SpringMVC和Portlet的帖子中读到,不推荐使用字段注入。据我所知,字段注入是指使用
@Autowired
注入Bean,如下所示:

@Component
public class MyComponent {
    @Autowired
    private Cart cart;
}
在我的研究期间,我还阅读了有关构造函数注入的内容:

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



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

味道的问题。这是你的决定

但我可以解释为什么我从不使用构造函数注入

  • 我不想为我所有的
    @Service
    @Repository
    @Controller
    bean实现构造函数。我的意思是,大约有40-50个豆子或更多。每次如果我添加一个新字段,我都必须扩展构造函数。不,我不想要也不必

  • 如果您的Bean(服务或控制器)需要注入大量其他Bean,该怎么办?具有4个以上参数的构造函数非常难看

  • 若我使用的是CDI,那个么构造函数与我无关


  • 编辑#1: Vojtech Ruzicka说:

    类具有太多依赖项,并且可能违反了单个 责任原则,应该重构

    对。理论与现实。 例如:
    DashboardController
    映射到单个路径
    *:8080/dashboard

    My
    dashboard Controller
    从其他服务收集大量信息,并将其显示在仪表板/系统概览页面中。我需要一个控制器。因此,我必须只保护这一条路径(基本身份验证或用户角色筛选器)

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


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

    注入类型

    对于如何将依赖项注入bean,有三个选项:

  • 通过构造函数
  • 通过setter或其他方法
  • 通过反射,直接进入领域
  • 您正在使用选项3。这就是当您在现场直接使用
    @Autowired
    时发生的情况


    注射指南

    一般指南(见或部分)如下:

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

    现场注入缺陷

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

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

    结论

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


    进一步阅读


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

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

    构造函数注入

    优点:

    • 更好的可测试性。单元测试中不需要任何模拟库或Spring上下文。您可以创建要使用新关键字测试的对象。这样的测试总是更快,因为它们不依赖于反射机制。(30分钟后被问到。如果作者使用了构造函数注入,它就不会出现)
    • 不变性。一旦设置了依赖项,就无法更改它们
    • 更安全的代码。在执行构造函数之后,您的对象就可以使用了,因为您可以验证作为参数传递的任何内容。对象可以是就绪的,也可以不是就绪的,两者之间没有状态。通过场注入,当对象脆弱时,引入中间步骤
    • 强制依赖关系的清晰表达。在这个问题上,现场注入是不明确的
    • 让开发人员思考设计。dit写了一个有8个参数的构造函数,这实际上是一个糟糕的设计和性能的标志。不管一个类在其构造函数或字段中是否有8个依赖项,它总是错误的。与通过字段相比,人们更不愿意向构造函数添加更多依赖项。它作为一个信号传递给你的大脑
      @Component
      public class MyComponent {
          private final Cart cart;
      
          @Autowired
          public MyComponent(Cart cart){
             this.cart = cart;
          }
      }