文档章节

Spring的@Autowired实践感知

chace0120
 chace0120
发布于 2015/12/17 13:32
字数 1376
阅读 3376
收藏 117

其实在工作中使用了Spring这么久,有很多的细节是值得使用者去思考的。现在笔者想针对Spring依赖注入的@Autowired总结一些想法。最近笔者看到一则实践建言,建议Spring的依赖注入采用构造器的方式(下面会提到)。看到这条,不免心中会有疑惑,为什么?

@Autowired的多种方式

先让我们来总结下,@Autowired的使用方式有哪些。根据文档上的说明,@Autowired注解有三种常用方式。一种是在构造器的前面使用,后续我们简称为“constructor方式”;一种是在setter方法前面使用,后续简称为“setter方式”;最后一种是直接在声明的类属性上使用,后续简称“field方式”。

相信看过Spring依赖注入示例代码、项目源码的人,对笔者上面提到的三种方式不会陌生,应该都有所见闻,而且应该知道@Autowired默认是依据类型来进行注入的。既然提供了三种方式,为什么那条建言推荐使用constructor方式呢?

各个方式的对比

笔者查阅了几篇相关的歪果仁所写的博客及帖子,其实可以发现很多人对这三种方式的对比和取舍早已争论不休,笔者大致总结了几方面。

constructor方式

@Service
public ProductionService {
	private final UserService userService;

	@Autowired
	public ProductionService(UserService userService){
		this.userService = userService;
	}

	//...省略
}

优势:

  1. 可以将依赖的属性设为final,避免了不期望的可变性。
  2. 在写测试用例时,这种方式的优势会更明显。写测试代码时,依赖的属性对象一般是通过mock实现的,但是脱离了Spring的依赖注入机制,如何将mock的对象进行赋值呢?通过构造器可以很好的完成这项任务。写过测试用例的人,应该对此非常赞同。但笔者对此不太苟同,假设采用了field方式,spring-test包现在提供了工具类可以实现将mock的对象赋值给测试对象的属性。

劣势:

  1. 无法再次配置或再次注入,当期望再次注入bean时,则必须重新构造一个新的实例。这项跟上面的优势对比,自相矛盾了,具体还得看你的应用场景了。但笔者未想到需要再次注入的场景,在一篇博客中看到一句“Management through JMX MBeans is a compelling use case”,希望了解的朋友可以指点一二。
  2. 如果当前类依赖的bean过多,那么构造器就会变得很笨拙了。从表象上看,这项说的确实在理,但从另一个角度来看,这项未必算是劣势。假如当前类依赖了过多的bean,这个类是否需要重新审视一下,是否需要重构呢?
  3. 存在循环依赖的风险。这点说的应该算戳中痛点了,若采用constructor方式,切记避免循环依赖。

setter方式

@Service
public ProductionService {
	private UserService userService;

	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	//...省略
}

优势:

  1. 对比constructor方式,很明显setter方式“重塑性”强。
  2. 同样可以解决测试时绑定mock对象的问题。
  3. 避免了依赖bean太多导致的构造器笨拙的现象。

劣势:

  1. 假设代码的应用场景渴望不可变性的话,那么setter方式自然暴露了太多。有人可能会提出,把依赖注入的属性设为final如何?既然你的本意不变,又暴露了可变的方法,岂不是自己打脸么。

field方式

@Service
public ProductionService {
	@Autowired
	private UserService userService;
	
	//...省略
}

优势:

  1. 咋一看,是不是“清爽”了许多?可以没有专门的构造器和setter方法,直接注解在属性上,简单明了。
  2. 避免了依赖bean太多导致的构造器笨拙的现象。但往往容易忽视了过多依赖导致的类结构的合理性,所以此项是优是劣,不是绝对的。

劣势:

  1. 写测试用例时无法直接绑定mock的依赖对象。但spring-test包中可以解决这个问题了。
  2. 没有“重塑性”。

综上所述,@Autowired的三种用法其实没有所谓的孰优孰劣,笔者也就不在此提倡哪种用法被喷了。使用者需要根据具体的应用场景,例如可变性的要求、“重塑性”的需要、测试时的方便、代码结构合理性等等因素吧,采用适合自己的方式。

笔者在做上述内容的思考时,想到了另外一个“话题”,不在本篇中叙述了,不然有些跑题。可以先抛个引子,在后续博文中探讨。“假设采用field方式注入bean,又想保证不可变性的话,能否把属性设为final呢?”

参考

  • I was wrong: Constructor vs. setter injection

https://steveschols.wordpress.com/2012/06/05/i-was-wrong-constructor-vs-setter-injection/

  • Why I Changed My Mind About Field Injection?

http://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about-field-injection/

  • Why field injection is evil

http://olivergierke.de/2013/11/why-field-injection-is-evil/

© 著作权归作者所有

共有 人打赏支持
chace0120
粉丝 38
博文 48
码字总数 41091
作品 0
安阳
程序员
私信 提问
加载中

评论(10)

Andrewc
Andrewc
个人偏向@inject 属于JSR标准, 而且标注field以后不需要setter即可注入
魔力猫
魔力猫

引用来自“cqian59420”的评论

我都是@resources ,还不知具体啥区别
一个是Spring自己的注解,一个是兼容EJB的注解。其实都一样。
cqian59420
cqian59420
我都是@resources ,还不知具体啥区别
小安安
小安安
然而...
chace0120
chace0120

引用来自“分流砥柱”的评论

1.constructor方式 不能懒加载,必须check null。2.@Autowired不仅这么多注入吧?应该可以在任何方法注入。3.你可以看看源文档和源码肯定收货更大。
笔者措辞有问题,已修正,改为了三种常用方式。
分流砥柱
分流砥柱
1.constructor方式 不能懒加载,必须check null。2.@Autowired不仅这么多注入吧?应该可以在任何方法注入。3.你可以看看源文档和源码肯定收货更大。
不是小白
不是小白
前后不呼应
站内留言
站内留言
@七哥 aop
南湖船老大
南湖船老大
还是field方式比较可取
oοゞ无缘早餐ゞοo
oοゞ无缘早餐ゞοo
不是很理解
Spring 注解 @Resource和@Autowired

Spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解,如:@Resource、 @PostConstruct及@PreDestroy。 1. @Autowired @Autowired是Spring 提供的,需导入 Package:...

zahschusheng
2015/10/27
0
0
Spring Cloud Eureka Server高可用之:在线扩容

本文共 1591字,阅读大约需要 6分钟 ! --- 概述 业务微服务化以后,我们要求服务高可用,于是我们可以部署多个相同的服务实例,并引入负载均衡机制。而微服务注册中心作为微服务化系统的重要...

CodeSheep
10/19
0
1
【Spring】Autowiredd原理及与Resource注解区别

Autowired注解 Autowired顾名思义,表示自动注入,如下是Autowired注解的源代码: 从Autowired的实现可以看到,Autowired可以用于类的构造方法,类的字段,类的方法以及注解类型上,但是Aut...

weknow
03/06
0
0
详解Java的Spring框架中的注解的用法

使用Spring注解来注入属性 1.1. 使用注解以前我们是怎样注入属性的 类的实现: 配置文件: 1.2. 引入@Autowired注解(不推荐使用,建议使用@Resource) 类的实现(对成员变量进行标注) 或者...

Airship
04/22
0
0
《Spring5学习》 01 装配Bean之自动化装配

Spring的自动化装配就便利性方面远远优于其他装配方法,这也是业界目前主要采用的Bean装配机制。Spring基于组建扫描和自动装配实现自动化装配,能将用户的显示配置降到最低。以下通过一段代码...

老韭菜
08/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

fabric增删改查Mac

备份1.3版本,重新下载1.1版本到fabric文件夹 /opt/gopath/src/github.com/hyperledger/fabric -> /opt/gopath/src/github.com/hyperledger/fabric1.3 新建/opt/gopath/src/github.com/hype......

八戒八戒八戒
22分钟前
2
0
盘点愚人节各大网站彩蛋,谁最爱恶搞?

如今的愚人节俨然已是各品牌宣传了一个重要节日,同时,也成为了各大互联网科技企业凑热闹,比拼创意和策划的节日。跟小编一起看看有哪些有趣的策划吧! Google地图变成吃豆人游戏 每年愚人节...

临江仙卜算子
46分钟前
3
0
Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析

本文分析的是源码,所以至少读者要熟悉它们的接口使用,同时,对于并发,读者至少要知道 CAS、ReentrantLock、UNSAFE 操作这几个基本的知识,文中不会对这些知识进行介绍。Java8 用到了红黑树...

java菜分享
47分钟前
3
0
玩手机与做实验

看过这样一个故事:说的是在二十世纪二十年代初的一个深夜,担任英国剑桥大学卡文迪许实验室主任的卢瑟福来实验室检查,发现一位学生还在做实验。卢瑟福就问他:“你上午做什么了?”学生回答...

Bob2100
今天
5
0
Kafka流式处理

Kafka Streams 初识流式处理 什么是数据流 数据流(也叫事件流)是无边界数据集的抽象表示。无边界意味着无限和持续增长。无边界数据集之所以是无限的,是因为随着时间的推移,新记录会不断加...

东都大狼狗
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部