前言
在我们使用Spring进行开发的时候,经常需要进行依赖注入,而@Autowired注解是一个常用的依赖注入方式,但是我们会发现当你使用@Autowired进行注入的时候,idea会出现一个黄色的下划线
idea会提醒field injection is not recommented 不推荐这种注入方式,而是更推荐构造器的方式进行注入,翻了下官网,Spring团队通常支持构造函数注入,确保当前注入的不能是null
构造器注入的优势
从官网的介绍上看,使用构造器主要是因为它有几个明显的好处
确保依赖不为 null
构造器注入要求在创建对象时就传入所有依赖,这样可以保证这些依赖不会为 null。而字段注入是在对象创建后才进行,可能会导致某些依赖没有正确注入,出现意料之外的错误。
如果使用@Autowired是可以接受一个不存在的Bean,你只要把required设置为false
@RestController
@RequestMapping("apiRequest")
public class ApiRequestController {
@Autowired(required = false)
private ApiRequestService apiRequestService;
}
public class ApiRequestServiceImpl implements ApiRequestService {
}
而如果使用构造器的方式的话,就必须保证这个bean必须存在
保持依赖的不可变性
构造器注入使依赖在对象创建后无法修改,从而保证对象的状态是稳定的。字段注入或Setter方法可以在对象的生命周期内修改依赖,增加了代码的不确定性和潜在的错误。
使用@Autowired字段注入的类状态可能随时发生变化,因为字段是可变的(虽然是private但非final):
可能出现的情况
@Autowired
private ApiRequestService apiRequestService;
public void test() {
this.apiRequestService = new ApiRequestServiceImpl();
}
与此相对,通过构造器注入,依赖可以设置为final,一旦对象创建后,依赖就不会再被更改:
循环依赖
当两个或多个类相互依赖时,就会出现循环依赖。由于存在这些依赖关系,因此无法构造对象,执行过程中可能会出现运行时错误或死循环。
使用字段注入可能会导致循环依赖关系被忽视:
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
我们知道依赖是在需要时注入,而不是在启动的时候进行注入,因此Spring不会抛出循环依赖错误
如果使用构造器的方式
@Component
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
通过构造函数注入的话,可以在程序编译的时候出现提醒
The dependencies of some of the beans in the application context form a cycle:
应用程序上下文中的某些bean的依赖关系形成了一个循环
如何解决循环依赖问题,在其中一个加上@Lazy注解
@Component
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
总结
本文介绍了为什么不推荐使用@Autowired的原因,虽然@Autowired使用起来比较方便,但是存在为Null、不可变和循环依赖问题,使用构造器注入就能完美解决这个
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。