近期看同事用idea开发的代码,发现在使用@Autowired的时候,大多使用构造函数进行注入。
以前自己在写代码的时候都是直接在变量上进行注入,也没注意过,查了些资料,发现如果直接在变量上进行注入,那么可能会造成NPE。
构造函数注入的方式:
public class TestController {
private final TestService testService;
@Autowired
public TestController(TestService testService) {
this.testService = testService;
}
…
}
变量注入的方式:
public class TestController {
@Autowired
private TestService testService;
…
}
那么为什么变量注入的方式可能会造成NPE?如下:
public class TestController {
@Autowired
private TestService testService;
private String testname;
public TestController(){
this.testname = testService.getTestName();
}
}
这段代码执行时会报NPE。
该类的构造函数中的变量值是通过TestService实例来调用TestService类中的方法获得,而Java类会先执行构造函数,然后在通过@Autowired注入实例,因此在执行构造函数的时候就会报错。
解决方案就是采用构造函数的注入方式,如下:
public class TestController {
private TestService testService;
private String testname;
@Autowired
public TestController(TestService testService){
this.testService = testService;
this.testname = testService.getTestName();
}
}
上面的方法中没有加入final来修饰,但是spring官方文档上是建议将成员变量加上final类型的,这是为什么呢?
有网友解释:
1.spring配置默认的bean的scope是singleton,可以通过设置bean的scope属性为prototype来声明该对象为动态创建。但是,如果你的service本身是singleton,注入只执行一次。
2.@Autowired本身就是单例模式,只会在程序启动时执行一次,即使不定义final也不会初始化第二次,所以这个final是没有意义的吧。
无论是spring的bean的scope是单例还是多例,成员变量加上了final后,只能被赋值一次,赋值后值不再改变。
注意:
1.如果使用变量注入的话,可能回导致循环依赖,即A里面注入B,B里面又注入A。
2.在代码中发现构造方法中注入了很多依赖,显得很臃肿,对于这个问题,说明类中有太多的责任,违反了类的单一性职责原则,这时候需要考虑使用单一职责原则进行代码重构。
参考资料:https://blog.csdn.net/qq_28587263/article/details/75570745