为了探寻 ‘@Resource’, ‘@Autowired’, 和‘@Inject’如何解决依赖注入中的问题,我创建了一个“Party”接口,和它的两个实现类“Person”,“Organization”。这样我就可以在注入Bean的时候不必使用具体类型(指使用接口类型即可)。这样做也方便我研究当一个接口有多个实现类与之匹配的时候Spring是如何解决依赖注入的不确定性的。

public interface Party {}
package com.sourceallies.person;
...
@Component
public class Person implements Party {}
package com.sourceallies.organization;
...
@Component
public class Organization implements Party {}

在Spring的配置文件中设置使用 ‘@Component’注解的两个实现类所在的包需要进行注入检查

<context:component-scan base-package="com.sourceallies.organization"/>
<context:component-scan base-package="com.sourceallies.person"/>
测试1:不明确的bean注入

这个测试验证注入Party的时候,当它有多个实现类的情况

@Resource
private Party party; @Autowired
private Party party; @Inject
private Party party;

以上三种情况抛出同样的 ‘NoSuchBeanDefinitionException’异常,单看异常名称意味着不存在对应的Bean,不过详细信息中显示找到了两个Bean。

org.springframework.beans.factory.NoSuchBeanDefinitionException:

No unique bean of type [com.sourceallies.Party] is defined:

expected single matching bean but found 2: [organization, person]

测试2:字段名称注入
@Resource
private Party person; @Autowired
private Party person; @Inject
private Party person;

其中@Resource注入可以设置可选项‘ name’属性,以下语法和上面的@Resource注解方式是等效的,但是@Autowired和@Inject就没有类似的等价方式了。

@Resource(name="person")
private Party party;

以上三种方式最终都被注入‘Person’ Bean。

测试3:字段类型注入
@Resource
private Person party; @Autowired
private Person party; @Inject
private Person party;

以上情况都将注入 ‘Person’ Bean。

测试4:以实现类的默认名进行注入
@Resource
@Qualifier("person")
private Party party; @Autowired
@Qualifier("person")
private Party party; @Inject
@Qualifier("person")
private Party party;

以上情况都将注入 ‘Person’ Bean。

测试5:指定实现类的类名

在实现类中使用‘Qualifier’注解指定注入时使用的名称

package com.sourceallies.person;
...
@Component
@Qualifier("personBean")
public class Person implements Party {}

注入的时候同样使用‘Qualifier’注解指定注入哪一个名称的实现类

@Resource
@Qualifier("personBean")
private Party party;
@Autowired
@Qualifier("personBean")
private Party party;
@Inject
@Qualifier("personBean")
private Party party;

以上情况都将注入 ‘Person’ Bean。

测试6:集合注入
@Resource
private List<Party> parties;
@Autowired
private List<Party> parties
@Inject
private List<Party> parties;

以上情况都将注入List中两个Bean。此方式同样可以用‘@Qualifier’限定注入Bean,每一个满足指定‘qualifier’的bean才会被注入到List中。

测试7:不良配置

用毫无关联的‘bad’作为‘@Qualifier’指定的匹配名

@Resource
@Qualifier("bad")
private Party person;
@Autowired
@Qualifier("bad")
private Party person;
@Inject
@Qualifier("bad")
private Party person;

这种情况下使用‘@Resource’注解将会忽略‘@Qualifier’配置,故而‘Person' Bean将被注入。

而后两者将会抛出 ‘NoSuchBeanDefinitionException’ 的错误信息,因为找不到与’@Qualifier‘配置相匹配的bean。

org.springframework.beans.factory.NoSuchBeanDefinitionException:

No matching bean of type [com.sourceallies.Party] found for dependency:

expected at least 1 bean which qualifies as autowire candidate for this dependency.

Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true),

@org.springframework.beans.factory.annotation.Qualifier(value=bad)}

总结

‘@Autowired’ 和‘@Inject’的报错信息完全相同,他们都是通过‘AutowiredAnnotationBeanPostProcessor’ 类实现的依赖注入,二者具有可互换性。

‘@Resource’通过 ‘CommonAnnotationBeanPostProcessor’ 类实现依赖注入,即便如此他们在依赖注入时的表现还是极为相近的,以下是他们在实现依赖注入时执行顺序的概括:

@Autowired and @Inject

  1. Matches by Type
  2. Restricts by Qualifiers
  3. Matches by Name

@Resource

  1. Matches by Name
  2. Matches by Type
  3. Restricts by Qualifiers (ignored if match is found by name)

‘@Resource’在依据name注入的时候速度性能表现的比 ‘@Autowired’ 和‘@Inject’优越,但这是微不足道的,不足以作为优先选择 ‘@Resource’的原因。我倾向于使用 ‘@Resource’是因为它配置起来更简洁。

@Resource(name="person")
@Autowired
@Qualifier("person")
@Inject
@Qualifier("person")

你也许会说使用字段 默认 名称作为注入时候的bean name,其他两种方式就会一样简洁:

@Resource
private Party person;
@Autowired
private Party person;
@Inject
private Party person;

确实如此。但是当你需要重构代码的时候又如何呢?使用’@Resource‘方式只需简单修改name属性即可,而无需触及注入Bean的名称(注入Bean的时候同意使用接口名称)。所以我建议使用注解方式实现注入的时候遵循以下语法风格:

1.在你的组件中明确限定bean名称而不是使用默认值[@Component("beanName")]。

2.同时使用’@Resource‘和它的’name'属性 [@Resource(name="beanName")]。

3.避免使用‘@Qualifier’注解,除非你要创建一系列类似beans的集合。例如,你也许需要建立一个set集合来存放一系列“规则”定义。这个时候可以选择‘@Qualifier'注解方式。这种方式使得将大量遵循相同规则的类放入集合中变得容易。

4.使用如下配置限定需要尽心组件扫描的包: [context:component-scan base-package="com.sourceallies.person"]。这样做可以减小spring扫描很多无效的包的情况。

遵循以上原则能增强你的,注解风格的,spring配置的可读性和稳定性。

spring下应用@Resource, @Autowired 和 @Inject注解进行依赖注入的差异的更多相关文章

  1. Spring Injection with @Resource, @Autowired and @Inject

    August 1st, 2011 by David Kessler Overview I’ve been asked several times to explain the difference b ...

  2. Spring 注释标签@Resource @Autowired 和@Inject的区别

    一些spring的开发人员在使用这三个标签进行注入的时候感到困惑.我来尝试解释一下这三个注解的主要区别.事实上,这三者非常相似,只存在一些微小的差别.在稍后的文章中会进行解释. @Resource-在 ...

  3. Spring @Resource, @Autowired and @Inject 注入

    Overview I’ve been asked several times to explain the difference between injecting Spring beans with ...

  4. 07 Spring框架 依赖注入(四)基于注解的依赖注入

    前面几节我们都在使用xml进行依赖的注入,但是在实际的开发中我们往往偏爱于使用注解进行依赖注入,因为这样更符合我们人的思维,并且更加快捷,本节就来讲述Spring基于注解的依赖注入: 信息注入注解 @ ...

  5. Spring-Context的注解实现依赖注入功能

    使用Spring-Context的注解实现依赖注入功能. Demo要点: 本例子中主要使用Annotation功能来实现对MoviceService的注入.我们将Cinema.java的头部标注为@C ...

  6. 【Spring Framework】Spring 入门教程(一)控制反转和依赖注入

    参考资料 Spring 教程 说在前面 什么样的架构,我们认为是一个优秀的架构? 判断准则:可维护性好,可扩展性好,性能. 什么叫可扩展性好? 答:在不断添加新的代码的同时,可以不修改原有代码,即符合 ...

  7. Spring @Resource,@Autowired,@Qualifier的注解注入和区别

    spring2.5提供了基于注解(Annotation-based)的配置,我们可以通过注解的方式来完成注入依赖.在Java代码中可以使用 @Resource或者@Autowired注解方式来经行注入 ...

  8. spring通过注解方式依赖注入原理 (私有成员属性如何注入)

    一.spring如何创建依赖的对象 用过spring的都知道我们在dao.service层加上@repository.@Service就能将这两个对象交给spring管理,在下次使用的时候使用@res ...

  9. Spring框架第四篇之基于注解的DI注入

    一.说明 与@Component注解功能相同,但意义不同的注解还有三个: 1)@Repository:注解在Dao实现类上 2)@Service:注解在Service实现类上 3)@Controlle ...

随机推荐

  1. P1117 [NOI2016]优秀的拆分

    $ \color{#0066ff}{ 题目描述 }$ 如果一个字符串可以被拆分为\(AABB\)的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串\(aab ...

  2. Chrome-headless 模式,没有UI界面的自动化UI测试

    如果在本机执行UI自动化脚本,打开的浏览器总是会不同程度的影响你做别的事情,那么我们可以采用 无界面运行我们的UI自动化,这种模式下运行脚本并不会真正地打开浏览器,整个过程都是在后台执行的.爽歪歪. ...

  3. editplus 编辑 php双击选中变量问题

    windows下,在很多地方双击鼠标左键可以选中一个连续的英文字符串. 在editplus 编辑器里可以双击选中一个变量,方便了编程,但是使用phptools(php.stx)增强语法插件后,在一个变 ...

  4. Ant demo

    <?xml version="1.0" encoding="UTF-8"?> <!-- 定义一个工程,默认任务为warFile. --> ...

  5. git 修改配置

    git config 查看配置信息 config 配置项帮助信息 $ git config config 配置有system级别 global(用户级别) 和local(当前仓库)三个设置项 从sys ...

  6. 安装orcle服务器端后,不需要安装客户端,可通过plsql登录

    用PL/SQL连接oracle数据库,不管是本地的还是远程的,一般都需要安装oracle客户端(500M左右)比较大,而且在各个系统上安装也有些讲究,需要修改相应配置文件,有点麻烦,像平时开发时候,我 ...

  7. Java - 自定义异常(尚学堂第六章异常机制作业计算平均数)

    编写一个计算N个学生分数平均分的程序.程序应该提示用户输入N的值,如何必须输入所有N个学生分数.如果用户输入的分数是一个负数,则应该抛出一个异常并捕获,提示“分数必须是正数或者0”.并提示用户再次输入 ...

  8. 透视效果shader(边缘光)

    思路:渲染两次. 1.第一次渲染:利用Greater进行深度测试,当目标被遮挡时,用一个边缘光的效果显示. 2.第二次渲染:正常渲染. 边缘光的思路:观察方向和顶点法向量夹角越大,边缘光越明显.边缘光 ...

  9. JSON中的坑

    坑一. 在使用localStorage时,我们会给一个key存取一个value,这个value可以是一个普通的字符串,也可以是一个对象,如果是一个字符串,我们就需要通过JSON.stringify来转 ...

  10. Apache-jmeter3.3安装

    一.首先检查机子上是否有安装jdk 检查方式,在cmd中输入java,出现如下信息,即已经安装好jdk 若未安装jdk,则看如下步骤 步骤一: 1.下载jdk,到官网下载jdk,地址:http://w ...