Spring依赖注入三种方式的对比
前言
由IDEA编码提示Field injection is not recommended引发的思考
依赖注入的三种方式
- 变量注入
- 构造器注入
- set方法注入
变量注入
@Autowired
private CoffeeRepository coffeeRepository;
实际上是通过反射实现注入。
缺点:
-
不允许不可变(
immutable)对象的声明(即final对象)Spring的IOC对待属性的注入使用的是set形式,但是final类型的变量在调用class的构造函数的这个过程当中就得初始化完成,这个是基于字段的依赖注入做不到的地方。只能使用基于构造函数的依赖注入的方式。
-
掩盖单一职责的设计思想
如果你采用的是基于构造函数的依赖注入 的方式来使用Spring的IOC的时候,当你注入的太多的时候,这个构造方法的参数就会很庞大,类似于下面。
当你看到这个类的构造方法那么多参数的时候,你自然而然的会想一下:这个类是不是违反了单一职责思想? .但是使用基于字段的依赖注入 不会让你察觉,你会很沉浸在@Autowire当中。
-
隐藏依赖性
当你使用Spring的IOC的时候,被注入的类应当使用一些public类型(构造方法,和setter类型方法)的方法来向外界表达:我需要什么依赖.但是基于字段的依赖注入 的方式,基本都是private形式的,private把属性都给封印到class当中了。
-
无法对注入的属性进行安检
基于字段的依赖注入 方式,你在程序启动的时候无法拿到这个类,只有在真正的业务使用的时候才会拿到,一般情况下,这个注入的都是非null的,万一要是null怎么办,在业务处理的时候错误才爆出来,时间有点晚了,如果在启动的时候就暴露出来,那么bug就可以很快得到修复(当然你可以加注解校验)。
-
使用单元测试有困难。
-
使得对应类无法脱离依赖注入容器进行运行。
构造器注入
private final CoffeeRepository coffeeRepository;
public CoffeeService(CoffeeRepository coffeeRepository) {
this.coffeeRepository = coffeeRepository;
}
Setter方法注入
private CoffeeRepository coffeeRepository;
@Autowired
public void setCoffeeRepository(CoffeeRepository coffeeRepository) {
this.coffeeRepository = coffeeRepository;
}
构造器注入 vs setter方法注入
以下引自官方文档:Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.
由上文可知:
- 构造器初始化为强制性依赖。而setter方法为可选依赖(即可能为null)。
- 使用构造器注入可以发现编码不合适的地方,当构造器的参数过多时,就可以考虑重构拆分此类。
总结
- 对于必须依赖或不可变对象,使用构造器注入。
- 对于可选依赖或可变对象,使用setter注入。
- 避免使用字段注入。

浙公网安备 33010602011771号