作者:汪军伍(处轩)
提到 Spring 依赖注入,大家最先想到应该是 @Resource 和 @Autowired,很多文章只是解说了性能上的区别,对于 Spring 为什么要反对两个这么相似的注解却未提到,属于知其然而不知其所以然。不知大家在应用这两个注解的时候有没有想过,@Resource 又反对名字又反对类型,还要 @Autowired 干嘛,难道是 Spring 官网没事做了?
真的是没事做了吗?读了本文你将会理解到:
- @Resource 和 @Autowired 起源
- Spring 官网为什么会反对这两个性能如此类似的注解?
- 为什么 @Autowired 属性注入的时候 Idea 会曝出黄色的正告?
- @Resource 和 @Autowired 举荐用法
起源
既然要弄清楚,就要先理解他们的身世。
@Resource 于 2006 年 5 月 11 日随着 JSR 250 公布,官网解释是:
Resource 正文标记了应用程序须要的资源。该注解能够利用于应用程序组件类,或组件类的字段或办法。当注解利用于字段或办法时,容器将在组件初始化时将所申请资源的实例注入到应用程序组件中。如果正文利用于组件类,则正文申明应用程序将在运行时查找的资源。
能够看到它相似一个定义,而由其余的组件或框架自在实现。
@Autowired 于 2007 年 11 月 19 日随着 Spring2.5 公布,同时官网也对 @Resource 进行了反对。@Autowired 的官网解释是:
将构造函数、字段、设置办法或配置办法标记为由 Spring 的依赖注入工具主动拆卸。
能够看到,@Autowired 是 Spring 的亲儿子,而 @Resource 是 Spring 对它定义的一种实现,它们的性能如此类似。那么为什么要反对了 @Resource,又要本人搞个 @Autowired 呢?
对此专门查了一下 Spring2.5 的官网文档,文档中有一段这么说到:
However, Spring 2.5 dramatically changes the landscape. As described above, the autowiring choices have now been extended with support for the JSR-250 @Resource annotation to enable autowiring of named resources on a per-method or per-field basis. However, the @Resource annotation alone does have some limitations. Spring 2.5 therefore introduces an @Autowired annotation to further increase the level of control.
大略的意思是说,Spring2.5 反对注解主动拆卸啦,现曾经反对 JSR-250 @Resource 基于每个办法或每个字段的命名资源的主动拆卸,然而只有 @Resource 是不行的,咱们还推出了“粒度”更大的 @Autowired,来笼罩更多场景了。
嗯哼,那么官网说的“粒度”就是要害了,那“粒度”指的是什么呢”?
既生“@Resource”,何生“@Autowired”
要想找到粒度是什么,咱们先从两个注解的性能下手
@Autowired
- 类型注入
@Resource
- 名字注入优先,找不到名字找类型
论性能的“粒度”,@Resource 曾经蕴含 @Autowired 了啊,“粒度”更大啊,难道是 Spring2.5 的时候还不是这样?我又去翻了下 Spring2.5 文档,下面明确的写到:
When using @Resource without an explicitly provided name, if no Spring-managed object is found for the default name, the injection mechanism will fallback to a type-match.
这不是和当初一样的吗,我此时凌乱了。那么“粒度”到底指的是什么?在混迹泛滥论坛后,其中 stackoverflow 的一段话引起了我的留神:
Both @Autowired and @Resource work equally well. But there is a conceptual difference or a difference in the meaning.
- @Resource means get me a known resource by name. The name is extracted from the name of the annotated setter or field, or it is taken from the name-Parameter.
- @Inject or @Autowired try to wire in a suitable other component by type.
So, basically these are two quite distinct concepts. Unfortunately the Spring-Implementation of @Resource has a built-in fallback, which kicks in when resolution by-name fails. In this case, it falls back to the @Autowired-kind resolution by-type. While this fallback is convenient, IMHO it causes a lot of confusion, because people are.
大略的意思是:Spring 尽管实现了两个性能相似的,然而存在概念上的差别或含意上的差别:
- @Resource 这按名称给我一个确定已知的资源。
- @Autowired 尝试按类型连贯适合的其余组件。
然而 @Resource 当按名称解析失败时会启动。在这种状况下,它会按类型解析,引起概念上的凌乱,因为开发者没有意识到概念上的差别,而是偏向于应用 @Resource 基于类型的主动拆卸。
原来 Spring 官网说的“粒度”是指“资源范畴”,@Resource 找寻的是确定的已知的资源,相当于给你一个坐标,你间接去找。@Autowired 是在一片区域外面尝试搜寻适合的资源。
所以下面的问题答案曾经根本明确了。
Spring 为什么会反对两个性能类似的注解呢?
- 它们的概念不同,@Resource 更偏向于找已知资源,而 Autowired 偏向于尝试按类型搜寻资源。
- 不便其余框架迁徙,@Resource 是一种标准,只有合乎 JSR-250 标准的其余框架,Spring 就能够兼容。
既然 @Resource 更偏向于找已知资源,为什么也有按类型注入的性能?
- 集体猜想:可能是为了兼容从 Spring 切换到其余框架,开发者就算只应用 Resource 也是放弃 Spring 弱小的依赖注入性能。
Spring 的区别对待
看到这置信大家对应用 @Resource 还是 @Autowired 有了本人的见解。在日常写代码中有个小细节不晓得大家有没有留神到,应用 @Autowired 在属性上的时候 Idea 会曝出黄色的正告,并且举荐咱们应用构造方法注入,而 Resource 就不会,这是为什么呢?正告如下:
为什么 @Autowired 在属性上的时候 Idea 会曝出黄色的正告,并且举荐咱们应用构造方法注入?
其实 Spring 文档中曾经给出了答案,次要有这几点:
1、申明不了常量的属性
基于属性的依赖注入不适用于申明为 final 的字段,因为此字段必须在类实例化时去实例化。申明不可变依赖项的惟一办法是应用基于构造函数的依赖项注入。
2、容易漠视类的繁多准则
一个类应该只负责软件应用程序性能的单个局部,并且它的所有服务都应该与该职责紧密结合。如果应用属性的依赖注入,在你的类中很容易有很多依赖,所有看起来都很失常。然而如果改用基于构造函数的依赖注入,随着更多的依赖被增加到你的类中,构造函数会变得越来越大,代码开始就开始呈现“异味”,收回明确的信号表明有问题。具备超过十个参数的构造函数分明地表明该类有太多的依赖,让你不得不留神该类的繁多问题了。因而,属性注入尽管不间接突破繁多准则,但它却能够帮你漠视繁多准则。
3、循环依赖问题
A 类通过构造函数注入须要 B 类的实例,B 类通过构造函数注入须要 A 类的实例。如果你为类 A 和 B 配置 bean 以互相注入,应用构造方法就能很快发现。
4、依赖注入强依赖 Spring 容器
如果您想在容器之外应用这的类,例如用于单元测试,不得不应用 Spring 容器来实例化它,因为没有其余可能的办法(除了反射)来设置主动拆卸的字段。
为什么 @Resource 没有呢?
在官网文档中,我没有找到答案,查了一些材料说是:@Autowired 是 Spring 提供的,一旦切换到别的 IoC 框架,就无奈反对注入了. 而 @Resource 是 JSR-250 提供的,它是 Java 规范,咱们应用的 IoC 容器应该和它兼容,所以即便换了容器,它也能失常工作。
@Autowired 和 @Resource 举荐用法
1. 什么场景用什么适合
记住一句话就行,@Resource 偏向于 确定性的繁多资源 ,@Autowired 为类型去匹配合乎此类型所有资源。
如汇合注入,@Resource 也是能够的,然而倡议应用 @Autowired。idea 左侧的小绿标能够看进去,不倡议应用 @Resource 注入汇合资源,实质上汇合注入不是繁多,也是不确定性的。
2. @Autowired 举荐用法
办法 1:应用构造函数注入(举荐)
原生版:
优雅版:应用 lombok 的 @RequiredArgsConstructor+private final
办法 2:set 注入
原生版:
优雅版:应用 lombok 的 @Setter