[翻译] 在spring/springboot中不使用@Autowired

依赖注入很爽,但是有很多人并不理解它的目的,并且更重要的是并不知道如何正确使用它。

高级开发:为什么你不用构造器注入而使用字段注入?
初级开发:什么是字段注入?我用的是@Autowired。

这是一个经常发生的简单对话。听起来微不足道,但是却有深刻的内在意义。缺少对事务为什么和怎么用的认识,可能会导致灾难性的代码。

让我们深入讨论不同的依赖注入类型,尽管我们之前讨论过什么时候和为什么用哪个注入类型。

依赖注入的类型

  1. 字段注入
  2. 构造器注入
  3. Setter 方法注入

字段注入

简单来说,声明一个变量,可能是私有的,然后添加@Autowired注解

@Autowired
private UserService userService;

构造器注入

简单来说,让Spring容器通过构造器直接注入依赖项

@RestController
public class UserController {

  private final UserService userService;

  public UserController(UserService userService){
    this.userService = userService;
  }
}

Setter方法注入——基本不用

和字段注入差不多,只是这里是将@Autowired注解放到setter方法上

private UserService userService;

@Autowired
public void setUserService(UserService userService){
  this.userService = userService;
}

它们有什么不一样

简短地说,

  • 字段注入通过反射设置私有变量的值
  • 构造器注入是在创建controller对象的时候注入
  • Setter方法注入是通过setter方法注入

现在,你知道了依赖注入的要点,你可以通过本博客之外的渠道继续探索。

没有悬念,直奔主题...

特性 构造器注入 字段注入 setter 方法注入
可靠性 因为不可变的变量,很可靠 可靠性差 可靠性差
可维护性 构造器注入可以帮助区分依赖项列表,让代码更可读 可以和其他字段混在一起,让追踪依赖项更难,可读性差 和字段注入一样
可测试性 Mock依赖变得更容易了,因为它们可以被Mock并通过构造函数传递,甚至不需要创建Spring上下文,从而支持更快更干净的测试 创建Mock bean和实际 bean 以及它们之间的转换很乏味,让Mock测试充满挑战 Mock 很容易,因为可以直接设置Mock对象
连续性 连续性好,因为整个应用都是用相似的代码和注入风格 连续性差,因为字段注入可能随意地在代码的任何地方 连续性差,因为setter注入可能随意地在代码的任何地方
弹性 缺乏弹性,因为在代码中强加了严格的设计规则 弹性好,开发者可以很容易添加新依赖 弹性好,开发者可以很容易添加新依赖
code review的容易程度 为了让reviewer更好的检测修改,任何开发者增加新依赖都需要修改多个构造器 由于依赖是被当成一个简单的字段添加的,reviewer可能不会注意它 由于依赖是被当成一个简单的setter添加的,reviewer可能不会注意它
修改代码 更符合SOLID原则的中的开闭原则。为了扩展或者增加新特性的任何修改都可能引起争论,因为要保持代码整洁 *添加无限制的新依赖 *添加无限制的新依赖
循环依赖 能够容易的检测循环以来并且修正它 不检测循环依赖 不检测循环以来
性能 最后但并非最不重要的一点是,构造函数注入意味着必须按照依赖项的正确顺序创建所有bean,这反过来增加了应用程序的启动时间 由于每个对象可以被独立的创建,在之后使用反射注入,启动时间更快 由于每个对象可以被独立的创建,在之后使用反射注入,启动时间更快

结论

由于构造器注入的可靠性和严密性,它永远是依赖注入的第一选择。

在构造器注入不可能的场景下,字段注入也可以被使用(避免循环依赖)。

其他考虑

在比较字段注入和构造函数注入时,一个被广泛讨论的关键点是必需依赖和可选依赖。

  • 很多人争论说,我们可以在可选情况下用字段注入,必须的依赖项用构造器,但是有可选依赖它本身看起来就不是一个好的设计。
  • 由于可选依赖是一个不限制的领域,任何开发者都可以说我的依赖是可选依赖而随意添加依赖项,最终造成代码质量降低。
  • 个人认为,如果你代码中需要一个依赖,那么它就是必须的。如果是可选的,那为什么要添加。这个说法是有争议的,因人而异。

原文地址:https://medium.com/engineering-zemoso/when-not-to-autowire-in-spring-spring-boot-93e6a01cb793

上一篇:关于@Autowired 有时注入成功,有时为null的神奇bug


下一篇:Spring注解 @Resource和@Autowired比较