Spring为什么建议构造器注入

在使用IDEA 进行Spring 开发的时候,在字段上面使用@Autowired注解的时候,IDEA 会有警告提示:

Spring为什么建议构造器注入

文章插图
 
翻译过来就是这个意思:不建议使用基于 field 的注入方式 。
Spring 开发团队建议:在Spring Bean 永远使用基于constructor 的方式进行依赖注入 。对于必须的依赖,永远使用断言来确认 。
为什么Spring 团队会提出这样的建议?直接使用这种基于 field 的注入方式有什么问题?
首先需要知道,Spring 中有这么3种依赖注入的方式 :
  • 基于 field 注入(属性注入)
  • 基于 setter 注入
  • 基于 constructor 注入(构造器注入)
1. 基于 field 注入【Spring为什么建议构造器注入】所谓基于 field 注入,就是在bean的变量上使用注解进行依赖注入 。本质上是通过反射的方式直接注入到field,所以private的成员也可以被注入具体的对象 。这是平常开发中看的最多也是最熟悉的一种方式,同时,也正是 Spring 团队所不推荐的方式 。比如:
@Autowiredprivate Svc svc;2. 基于 setter 方法注入通过对应变量的setXXX()方法以及在方法上面使用注解,来完成依赖注入 。比如:
private Helper helper;@Autowiredpublic void setHelper(Helper helper) {this.helper = helper;}注:在 Spring 4.3 及以后的版本中,setter 上面的 @Autowired 注解是可以不写的 。
3. 基于 constructor 注入将各个必需的依赖全部放在带有注解构造方法的参数中,并在构造方法中完成对应变量的初始化,这种方式,就是基于构造方法的注入,也是日常最为推荐的一种使用方式 。这种注入方式很直接,通过对象构建的时候建立关系,所以这种方式对对象创建的顺序会有要求,当然Spring会搞定这样的先后顺序,除非出现循环依赖,然后就会抛出异常 。比如:
private final Svc svc;@Autowiredpublic HelpService(@Qualifier("svcB") Svc svc) {this.svc = svc;}在 Spring 4.3 及以后的版本中,如果这个类只有一个构造方法,那么这个构造方法上面也可以不写 @Autowired 注解 。
Spring 开发团队的建议
  • 强制依赖就用构造器方式
  • 可选、可变的依赖就用setter 注入当然可以在同一个类中使用这两种方法 。构造器注入更适合强制性的注入旨在不变性,Setter注入更适合可变性的注入 。
Spring 团队提倡使用基于构造方法的注入,因为这样一方面可以将依赖注入到一个不可变的变量中 (注:final 修饰的变量),另一方面也可以保证这些变量的值不会是 null。此外,经过构造方法完成依赖注入的组件 (注:比如各个 service),在被调用时可以保证它们都完全准备好了。与此同时,从代码质量的角度来看,一个巨大的构造方法通常代表着出现了代码异味,这个类可能承担了过多的责任。
基于 setter 的注入,则只应该被用于注入非必需的依赖,同时在类中应该对这个依赖提供一个合理的默认值 。如果使用 setter 注入必需的依赖,那么将会有过多的 null 检查充斥在代码中 。使用 setter 注入的一个优点是,这个依赖可以很方便的被改变或者重新注入。




    推荐阅读