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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398791.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

研究笔记:iOS中使用WebViewProxy拦截URL请求

本文为阿里iOS开发工程师阳翼所作。 先说明下iOS中加载url的正常流程: 1.客户端发送NSURLRequest给server 2.server返回对应的NSURLResponse 如果被WebViewProxy拦截,则流程变为: 1.客户端发送NSURLRequest给server 2.这个request被WebV…

seo超强外部链接、内部链接技巧

轮链-混链对做内外链都是非常有效果的! 外连,之于大家并不陌生,增加外链的方法也海了去,如软文推广、博客推广、友情链接等等等等,在这里我就不再累述,最近在一些文章里看到轮链和混链的SEO优化技巧&#x…

王道操作系统考研笔记——1.1.5 中断和异常

如果这篇博客对您有用的话,可以给我点个赞吗,这对我很重要,谢谢!❤️ 文章目录1.1.5 中断和异常1.1.5.1 中断机制的诞生1.1.5.2 中断的概念和作用1.1.5.3 中断的分类1.1.5.4 小结1.1.5 中断和异常 知识总览 1.1.5.1 中断机制的诞…

0101代码构成了计算机语言,计算机(全国一级考试)理论复习要点、模拟题.doc

第一部分 计算机基础知识计算机是能超高速自动进行算术运算和逻辑运算的电子机器;第一台计算机诞生于1946年(取名为ENIAC),在短短的50多年时间,已经历了四代:第一代电子管计算机、第二代晶体管计算机、第三代集成电路计算机(中小规…

PHP gd库 验证码

需要的简单前台页面 <html><head><meta http-equivContent-Type contenttext/html; charsetutf-8><title>验证码</title></head><script type"text/javascript"> function yanz() { document.getElementById…

LR+Jenkins实践思路

思路&#xff1a;在Loadrunner的安装bin目录下有Loadrunner Control模块的启动程序 “Wlrun.exe”&#xff0c;想利用Jenkin的 windows的batch命令持续构建一个任务&#xff0c;自动启动运行场景&#xff0c;且把结果发给analysis 通过Batch来调用LR场景&#xff1a; Loadrunne…

android中的tabdemo

首先先样式&#xff0c;注意必须用android:id/tabs 不能使用id <TabHost android:layout_height"match_parent"android:layout_width"match_parent"android:id"android:id/tabhost"xmlns:android"http://schemas.android.com/apk/res/an…

并行计算——基础并行计算

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 文章目录2 基础并行计算2.1 并行算法的基础知识2.1.1 并行算法的基本概念2.1.2 并行算法的表达2.1.3 并行算法的复杂性度量2.1.3.1 概述2.1.3.2 串行和并行算法…

计算机综合试验,计算机综合实验1.doc

计算机综合实验1.doc《计算机实用技术》实验报告实验序号&#xff1a;一      实验项目名称&#xff1a;综合实验1学  号姓  名专业、班实验地点指导教师时间2010.10.一、实验目的及要求1.熟悉Windows2000(XP)基本操作2.掌握在Windows2000(XP)资源管理器中文件和文件夹…

Go语言中cannot convert adminname (type interface {}) to type *: need type assertion的解决办法...

解决的办法是把string(adminname)替换为adminname.(string)。其它类型也是类似。转载于:https://www.cnblogs.com/huanhang/p/8352707.html

inotify-tools使用方法介绍

inotify-tools使用方法介绍文章目录[隐藏]安装方法使用例子inotifywaitinotifywatch参数说明inotifywaitinotifywatch可监听事件inotify-tools 是为linux下inotify文件监控工具提供的一套c的开发接口库函数&#xff0c;同时还提供了一系列的命令行工具&#xff0c;这些工具可以…

王道操作系统考研笔记——2.1.1 进程的定义、组成、组织方式和特征

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 文章目录2.1.1 进程的定义、组成、组织方式和特征2.1.1.1 进程的定义2.1.1.2 进程的定义2.1.1.3 进程的组成2.1.1.4 进程的组织2.1.1.5 链接方式2.1.1.6 索引方…

服务器换账号登陆不了怎么办,怎么切换账号 更换账号 注册新的账号小技巧分享给你...

很多玩家喜欢多尝试几种玩法&#xff0c;那么万国觉醒怎么切换账号&#xff1f;切换账号后玩家如何再重新登入游戏&#xff1f;如何在多个账号中快速切换&#xff1f;今天小编就跟大家说说万国觉醒快速切换账号登入游戏的技巧。一、切换账号介绍我们常说的切换账号有两种意思&a…

vue基本介绍

https://cn.vuejs.org/v2/guide/ Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既…

android控件的隐藏与显示

2019独角兽企业重金招聘Python工程师标准>>> visibility&#xff1a;显示 invisibility&#xff1a;不显示&#xff0c;不可见但是仍然占据空间 gone&#xff1a;不显示&#xff0c;不可见不占用空间 view.setVisibility();----设置值&#xff1a;0代表visibility&a…

《BI那点儿事》Microsoft 线性回归算法

Microsoft 线性回归算法是 Microsoft 决策树算法的一种变体&#xff0c;有助于计算依赖变量和独立变量之间的线性关系&#xff0c;然后使用该关系进行预测。该关系采用的表示形式是最能代表数据序列的线的公式。例如&#xff0c;以下关系图中的线是数据最可能的线性表示形式。 …

王道操作系统考研笔记——2.1.2 进程的状态和转换

如果这篇博客对您有用的话&#xff0c;可以给我点个赞吗&#xff0c;这对我很重要&#xff0c;谢谢&#xff01;❤️ 2.1.2 进程的状态和转换 知识总览 2.1.2.1 三种基本状态 进程是程序的一次执行。在这个执行过程中&#xff0c;有时进程正在被CPU处理&#xff0c;有时又需要…

PHP表达式

自定义常量define()函数&#xff1a;专门用于定义自定义常量&#xff1b; 语法格式&#xff1a;define(name,value[,boolean case_insensitive]);函数功能&#xff1a;定义一个名字为name&#xff0c;值为value的常量。 case_insensitive参数的默认值为FALSE,…

Java中抽象类和接口在概念、语法和应用上的区别和关系

2019独角兽企业重金招聘Python工程师标准>>> 春招开始了&#xff0c;盆友们都忙着准备笔试、准备面试&#xff0c;复习学过的知识点&#xff0c;当然我也不例外&#xff0c;在这里祝每一个"有心人"心想事成&#xff0c;梦圆2016&#xff0c;加油&#xff…

跳槽

2008年6月26日 阴天多云 辞职前第16日 土耳其不争气&#xff0c;害的我输了近4000分的可用分&#xff0c;最为倒霉的是它尽然先进球&#xff0c;给了我那么多的希望。还有就是直播过程中突然的长时间的无信号&#xff0c;输都不知道怎么输的。 今天瞌睡比较重&#xff0c;上班的…