目录


  • 问题背景
  • @Autowired和构造方法执行顺序差异
  • 解决方案
  • 为什么要加final?


问题背景

使用@Autowired注解时,发现IDEA报了一个 warning!

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_构造函数

追求极致的程序员怎么受得了这玩意?

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_构造方法_02

  • 还得再点击那三小点点!然后继续点!
    @Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_构造方法_03
    @Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_spring_04


Spring Team recommends “Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies”.


和阿里编码规范推荐似的,Spring团队推荐又来了:总是在您的bean中使用构造函数建立依赖注入。总是使用断言强制依赖”。

直接​​alt+enter​​写成这样子

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_构造函数_05

好了,终于没大波浪了。

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_构造方法_06

可是对真理充满追求的程序员又开始抓狂了,为啥这就不警告了呢????

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_spring_07

众所周知,@Autowired 可以对成员变量、方法以及构造方法三种方式操作。


那么成员变量和构造方法设置又有什么区别呢?


@Autowired注入bean,相当于在配置文件中配置bean,并且使用setter注入。而对构造方法,就相当于是使用构造函数进行依赖注入了吧。莫非是这两种注入方法的不同???

@Autowired和构造方法执行顺序差异

先看一段代码,下面的代码能运行成功吗?

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_spring_08

不能。

因为Java类会先执行构造方法,然后再给注解了@Autowired 的user注入值。


Java变量的初始化顺序:静态变量或静态语句块–>实例变量或初始化语句块–>构造方法–>@Autowired


所以在执行构造方法时,就会报错。报错信息可能会像


Exception in thread “main” org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘…’ defined in file […class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate […]: Constructor threw exception; nested exception is java.lang.NullPointerException


创建Bean时出错,出错原因是实例化bean失败,因为bean时构造方法出错,在构造方法里抛NPE。

解决方案

通过构造方法注入

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_spring_09

使用构造方法注入,可以明确成员变量的加载顺序。

@Autowired注解你真的会用吗?Spring官方有话说:Always use constructor based dependency injection in your beans_spring_10

可细心地程序员不止于此,还有个问题

为什么要加final?


  1. spring配置默认的bean的scope是singleton,也就是启动后一直有。通过设置bean的scope属性为prototype来声明该对象为动态创建。但是,如果你的service本身是singleton,注入只执行一次。@Autowired本身就是单例模式,只会在程序启动时执行一次,即使不定义final也不会初始化第二次,所以这个final是没有意义的吧。可能是为了防止,在程序运行的时候,又执行了一遍构造函数;
  2. 或者是更容易让人理解的意思,加上final只会在程序启动的时候初始化一次,并且在程序运行的时候不会再改变。