乐趣区

关于阿里云:Spring探索丨既生Resource何生Autowired

作者:汪军伍(处轩)

提到 Spring 依赖注入,大家最先想到应该是 @Resource 和 @Autowired,很多文章只是解说了性能上的区别,对于 Spring 为什么要反对两个这么相似的注解却未提到,属于知其然而不知其所以然。不知大家在应用这两个注解的时候有没有想过,@Resource 又反对名字又反对类型,还要 @Autowired 干嘛,难道是 Spring 官网没事做了?

真的是没事做了吗?读了本文你将会理解到:

  1. @Resource 和 @Autowired 起源
  2. Spring 官网为什么会反对这两个性能如此类似的注解?
  3. 为什么 @Autowired 属性注入的时候 Idea 会曝出黄色的正告?
  4. @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

退出移动版