当我们在使用依赖注入的时候,通常有三种方式:

1.通过构造器来注入;

2.通过setter方法来注入;

3.通过filed变量来注入;

那么他们有什么区别吗?应该选择哪种方式更好?

代码示例:

Constructor

 1 private DependencyA dependencyA;
 2 private DependencyB dependencyB;
 3 private DependencyC dependencyC;
 4
 5 @Autowired
 6 public DI(DependencyA dependencyA, DependencyB dependencyB, DependencyC dependencyC) {
 7     this.dependencyA = dependencyA;
 8     this.dependencyB = dependencyB;
 9     this.dependencyC = dependencyC;
10 }

Setter

 1 private DependencyA dependencyA;
 2 private DependencyB dependencyB;
 3 private DependencyC dependencyC;
 4
 5 @Autowired
 6 public void setDependencyA(DependencyA dependencyA) {
 7     this.dependencyA = dependencyA;
 8 }
 9
10 @Autowired
11 public void setDependencyB(DependencyB dependencyB) {
12     this.dependencyB = dependencyB;
13 }
14
15 @Autowired
16 public void setDependencyC(DependencyC dependencyC) {
17     this.dependencyC = dependencyC;
18 }

Field

1 @Autowired
2 private DependencyA dependencyA;
3
4 @Autowired
5 private DependencyB dependencyB;
6
7 @Autowired
8 private DependencyC dependencyC;

三种方式的区别小结:

1.基于constructor的注入,会固定依赖注入的顺序;该方式不允许我们创建bean对象之间的循环依赖关系,这种限制其实是一种利用构造器来注入的益处 - 当你甚至没有注意到使用setter注入的时候,Spring能解决循环依赖的问题;

2.基于setter的注入,只有当对象是需要被注入的时候它才会帮助我们注入依赖,而不是在初始化的时候就注入;另一方面如果你使用基于constructor注入,CGLIB不能创建一个代理,迫使你使用基于接口的代理或虚拟的无参数构造函数。

3.相信很多同学都选择使用直接在成员变量上写上注解来注入,正如我们所见,这种方式看起来非常好,精短,可读性高,不需要多余的代码,也方便维护;

缺点:

1.当我们利用constructor来注入的时候,比较明显的一个缺点就是:假如我们需要注入的对象特别多的时候,我们的构造器就会显得非常的冗余、不好看,非常影响美观和可读性,维护起来也较为困难;

2.当我们选择setter方法来注入的时候,我们不能将对象设为final的;

3.当我们在field变量上来实现注入的时候

a.这样不符合JavaBean的规范,而且很有可能引起空指针;

b.同时也不能将对象标为final的;

  c.类与DI容器高度耦合,我们不能在外部使用它;

d.类不通过反射不能被实例化(例如单元测试中),你需要用DI容器去实例化它,这更像集成测试;

... etc.

来自Spring官方文档的建议:  
在Spring 3.x 中,Spring团队建议我们使用setter来注入:

大致是说大量的构造器参数会显得非常笨重,尤其是当属性是可选的时候。setter方法可以使类的对象在后来重新配置或者重新注入。提供所有的依赖意味着对象总是返回一个完全初始化状态的client客户端(调用)。缺点是对象变得不那么适合重新配置和重新注入。

而在Spring 4.x 中,Spring团队不再建议我们使用setter来注入,改为了constructor:

Spring团队通常建议使用构造器来注入,因为它允许一个应用程序组件实现为不可变对象,并确保所需的依赖项不是空。此外构造器注入组件总是返回一个完全初始化状态的client客户端(调用)。附注,大量的构造函数参数是一个糟糕的代码习惯,看起来也很坏,这意味着类可能有太多的责任,应该被重构,以更好地解决适当的关注点分离。

setter方法只应该主要的用在可以在类中指定合理的默认值的可选的依赖关系。否则,用到依赖的所有地方都应该进行非空检查。setter注入的一个好处是,setter方法使类的对象可以在之后重新配置或者重新注入。

(以上是本人的渣渣英语翻译结合有道得来。。大佬看到请轻喷)

接下来插播一条Spring 4.3 的新特征:

在Spring 4.3 以后,如果我们的类中只有单个构造函数,那么Spring就会实现一个隐式的自动注入,上代码:

之前:

 1 @Service
 2 public class FooService {
 3
 4     private final FooRepository repository;
 5
 6     @Autowired
 7     public FooService(FooRepository repository) {
 8         this.repository = repository
 9     }
10 }

在Spring 4.3 之后:

1 @Service
2 public class FooService {
3
4     private final FooRepository repository;
5
6     public FooService(FooRepository repository) {
7         this.repository = repository
8     }
9 }

如我们所见,我去掉了构造器上的@Autowired注解,经测试后发现,程序能正常运行,repository的依赖也被成功注入了,当时感觉就很amazing。。有兴趣的同学可以试试~

总结:

1.强制性的依赖性或者当目标不可变时,使用构造函数注入(应该说尽量都使用构造器来注入

2.可选或多变的依赖使用setter注入(建议可以使用构造器结合setter的方式来注入

3.在大多数的情况下避免field域注入(感觉大多数同学可能会有异议,毕竟这个方式写起来非常简便,但是它的弊端确实远大于这些优点

4.Spring 4.3+ 的同学可以试一试构造器的隐式注入,采用此方式注入后,使得我们的代码更优雅,更独立,减少了对Spring的依赖性。

ps: 转载请标注出处谢谢。

转载于:https://www.cnblogs.com/chansblogs/p/8343930.html

Spring注解依赖注入的三种方式的优缺点以及优先选择相关推荐

  1. spring依赖注入的三种方式以及优缺点

    spring依赖注入的三种方式以及优缺点 一.依赖注入的三种方式 1.通过构造器注入.(spring4.3之后,推荐使用) 2.通过setter注入.(spring4.3之前,推荐使用) 3通过fil ...

  2. java中四种注入注解,Spring中依赖注入的四种方式

    在Spring容器中为一个bean配置依赖注入有三种方式: · 使用属性的setter方法注入  这是最常用的方式: · 使用构造器注入: · 使用Filed注入(用于注解方式). 使用属性的sett ...

  3. Spring系列之依赖注入的三种方式

    目录 一.依赖注入方式 1.使用属性的setXXX方法注入 2.构造函数注入 (1)按类型匹配入参type (2)按索引匹配入参index (3)联合使用类型和索引匹配入参[type和index一起使 ...

  4. Spring实现依赖注入的几种方式

    Spring实现依赖注入的几种方式 1.基于有参构造实现 <bean id="user" class="com.ccu.twj"><const ...

  5. 05.bean依赖注入的三种方式

    05.bean依赖注入的三种方式 1.概述 依赖注入 DI(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现. 在编写程序时,通过控制反转,把对象的创建交给 ...

  6. php依赖注入的三种方式

    控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(Dependency Inject ...

  7. Spring依赖注入的三种方式(好的 坏的和丑的)

    关于spring bean三种注入方式的优缺点对比,翻译自Spring DI Patterns: The Good, The Bad, and The Ugly,水平有限,如有错误请指正. Sprin ...

  8. java调用外联服务用xml,Spring IOC 依赖注入的两种方式:XML和注解

    IoC,直观地讲,就是容器控制程序之间的关系,而非传统实现中,由程序代码直接操控.这也就是所谓"控制反转"的概念所在.控制权由应用代码中转到了外部容器,控制权的转移是所谓反转.Io ...

  9. 依赖注入的三种方式_一起学Spring之三种注入方式及集合类型注入

    本文主要讲解Spring开发中三种不同的注入方式,以及集合数据类型的注入,仅供学习分享使用,如有不足之处,还请指正. 概述 Spring的注入方式一共有三种,如下所示: 通过set属性进行注入,即通过 ...

最新文章

  1. Android–多线程之Handler下载图片源码
  2. 002_Spring Data JPA CRUD
  3. linux下镜像播放视频,linux下挂载iso镜像的方法
  4. java 持久化线程_java – Spring Hibernate Envers多线程 – 会话关...
  5. javascript 图表_JavaScript 2018年的三个有争议的图表
  6. 基于IO流读取的 完成 用户登录,注册,修改,查看所有用户,删除功能
  7. 被面试官虐过之后,他轻蔑的问我:你还说你了解单例模式吗?
  8. php.exe不是内部或外部命令,“php.exe”不被识别为内部或外部命令,可操作程序或batch file...
  9. Vue2 使用Volar 报错:<template v-for> key should be placed on the <template> tag
  10. python ftp_Python FTP
  11. LOJ2330「清华集训 2017」榕树之心
  12. 「转」101个著名的心理效应
  13. 巴斯勒相机的ip掩码_子网掩码计算器让IP掩码计算不再难!
  14. 服务器命令压缩文件,使用linux的zip命令压缩文件
  15. 开源多云技术平台——Choerodon猪齿鱼发布0.24版本
  16. 树莓派制作游戏机教程
  17. myeclipse10异常闪退Java was started but returned exit code=1
  18. aecmap快捷键_ARCMAP快捷键总结
  19. 2022年5月22日-Taylor级数的python实验
  20. Maven依赖jar包的查询

热门文章

  1. Snipaste截图
  2. Spark常见问题解决办法
  3. linux命令-vim命令模式
  4. 网页制作中如何自定义网页图标
  5. Ubuntu安装桌面环境
  6. Rancher中的服务升级实验
  7. 2.12 priority_queue
  8. MP实战系列(十七)之乐观锁插件
  9. Android系统启动系列----init进程
  10. dataTables本地刷新数据解决只能初始化一次问题