依赖注入很爽,但是有很多人并不理解它的目的,并且更重要的是并不知道如何正确使用它。
高级开发:为什么你不用构造器注入而使用字段注入?
初级开发:什么是字段注入?我用的是@Autowired。
这是一个经常发生的简单对话。听起来微不足道,但是却有深刻的内在意义。缺少对事务为什么和怎么用的认识,可能会导致灾难性的代码。
让我们深入讨论不同的依赖注入类型,尽管我们之前讨论过什么时候和为什么用哪个注入类型。
依赖注入的类型
- 字段注入
- 构造器注入
- 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