一文让您搞清楚@Resources, @Inject和@Autowired的区别
导航目录
- @Resources
- Match by Name
- Match by Type
- Match by Qualifier
- @Inject
- Match by Type
- Match by Qualifier
- Match by Name
- @Autowired
本文简述这三个Spring应用里常用的注解区别。
@Resources
官方文档里对@Resources的说明:
The @Resource annotation is part of the JSR-250 annotation collection and is packaged with Jakarta EE.
什么是JSR-250呢?访问这个链接:https://jcp.org/en/jsr/detail?id=250
里面有很多PDF可以下载:
打开一看,其实就是Java支持的注解的文档。这些文档是最权威的:
文档里介绍,@Resources对Bean的注入按照如下的优先级进行:
- Match by Name
- Match by Type
- Match by Qualifier
Match by Name
我们来看看Match by name的例子。下面的代码试图通过Match by Name注入一个名称为namedFile的Bean:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,classes=ApplicationContextTestResourceNameType.class)
public class FieldResourceInjectionIntegrationTest {@Resource(name="namedFile")private File defaultFile;@Testpublic void givenResourceAnnotation_WhenOnField_ThenDependencyValid(){assertNotNull(defaultFile);assertEquals("namedFile.txt", defaultFile.getName());}
}
Bean的定义在如下代码里:
@Configuration
public class ApplicationContextTestResourceNameType {@Bean(name="namedFile")public File namedFile() {File namedFile = new File("namedFile.txt");return namedFile;}
}
运行时,申明Bean依赖处的@Resource的Name属性和Bean定义处@Bean的Name属性值一致,Match by Name测试通过。
Match by Type
将使用bean的消费者代码里@Resource注解的name属性去掉,使其变成下面这样:
@Resource
private File defaultFile;
测试仍然通过,是因为Match by Name的探测机制执行失败后,进行下一轮Match by Type的探测,这一轮成功了。
Match by Qualifier
定义两个Bean:
@Configuration
public class ApplicationContextTestResourceQualifier {@Bean(name="defaultFile")public File defaultFile() {File defaultFile = new File("defaultFile.txt");return defaultFile;}@Bean(name="namedFile")public File namedFile() {File namedFile = new File("namedFile.txt");return namedFile;}
}
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,classes=ApplicationContextTestResourceQualifier.class)
public class QualifierResourceInjectionIntegrationTest {@Resourceprivate File dependency1;@Resourceprivate File dependency2;@Testpublic void givenResourceAnnotation_WhenField_ThenDependency1Valid(){assertNotNull(dependency1);assertEquals("defaultFile.txt", dependency1.getName());}@Testpublic void givenResourceQualifier_WhenField_ThenDependency2Valid(){assertNotNull(dependency2);assertEquals("namedFile.txt", dependency2.getName());}
}
这一次执行失败,遇到异常org.springframework.beans.factory.NoUniqueBeanDefinitionException.
原因是因为我们的测试代码里,没有指定注入Bean的名称,因此Spring的Match by Name探测失败,进行Match by Type时,探测到两个类型一样的Bean,Spring框架不知道注入哪一个,所以就报异常了。
避免这个异常也很容易,使用@Qualifier.代码如下:
@Resource
@Qualifier("defaultFile")
private File dependency1;@Resource
@Qualifier("namedFile")
private File dependency2;
@Inject
这个注解定义在JSR-330里,文档链接:
https://jcp.org/en/jsr/detail?id=330
注入的优先级:
- Match by Type
- Match by Qualifier
- Match by Name
Match by Type
注意@Inject注入的最高优先级方式为Match by Type,而非@Resource的Match by Name.
任意定义一个待注入的Component:
@Component
public class ArbitraryDependency {private final String label = "Arbitrary Dependency";public String toString() {return label;}
}
使用@Inject注入:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,classes=ApplicationContextTestInjectType.class)
public class FieldInjectIntegrationTest {@Injectprivate ArbitraryDependency fieldInjectDependency;@Testpublic void givenInjectAnnotation_WhenOnField_ThenValidDependency(){assertNotNull(fieldInjectDependency);assertEquals("Arbitrary Dependency",fieldInjectDependency.toString());}
}
Match by Qualifier
定义一个新的待注入组件:
public class AnotherArbitraryDependency extends ArbitraryDependency {private final String label = "Another Arbitrary Dependency";public String toString() {return label;}
}
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,classes=ApplicationContextTestInjectQualifier.class)
public class FieldQualifierInjectIntegrationTest {@Injectprivate ArbitraryDependency defaultDependency;@Injectprivate ArbitraryDependency namedDependency;@Testpublic void givenInjectQualifier_WhenOnField_ThenDefaultFileValid(){assertNotNull(defaultDependency);assertEquals("Arbitrary Dependency",defaultDependency.toString());}@Testpublic void givenInjectQualifier_WhenOnField_ThenNamedFileValid(){assertNotNull(defaultDependency);assertEquals("Another Arbitrary Dependency",namedDependency.toString());}
}
和之前@Resource的第一次试图通过Match by Type注入一样失败,遇到异常:NoUniqueBeanDefinitionException
利用@Qualifier避免这个异常:
@Inject
@Qualifier("defaultFile")
private ArbitraryDependency defaultDependency;@Inject
@Qualifier("namedFile")
private ArbitraryDependency namedDependency;
Match by Name
public class YetAnotherArbitraryDependency extends ArbitraryDependency {private final String label = "Yet Another Arbitrary Dependency";public String toString() {return label;}
}
消费者代码:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,classes=ApplicationContextTestInjectName.class)
public class FieldByNameInjectIntegrationTest {@Inject@Named("yetAnotherFieldInjectDependency")private ArbitraryDependency yetAnotherFieldInjectDependency;@Testpublic void givenInjectQualifier_WhenSetOnField_ThenDependencyValid(){assertNotNull(yetAnotherFieldInjectDependency);assertEquals("Yet Another Arbitrary Dependency",yetAnotherFieldInjectDependency.toString());}
}
application context代码:
@Configuration
public class ApplicationContextTestInjectName {@Beanpublic ArbitraryDependency yetAnotherFieldInjectDependency() {ArbitraryDependency yetAnotherFieldInjectDependency =new YetAnotherArbitraryDependency();return yetAnotherFieldInjectDependency;}
}
测试通过
@Autowired
这个注解和@Inject的用法一致,唯一区别就是@Autowired 属于Spring框架提供的注解。例子略。
要获取更多Jerry的原创文章,请关注公众号"汪子熙":
一文让您搞清楚@Resources, @Inject和@Autowired的区别相关推荐
- spring中@Inject和@Autowired的区别?分别在什么条件下使用呢?
问题:spring中@Inject和@Autowired的区别?分别在什么条件下使用呢? 我在浏览SpringSource上的一些博客,在其他一个博客中,那个作者用了@Inject,但是我觉得他用@A ...
- @Inject.@Resource.@Autowired 的区别
@Inject:Struts2的注解, @Resource : J2EE提供,用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name="beanName") ...
- 一文带你搞懂从动态代理实现到Spring AOP
摘要:本文主要讲了Spring Aop动态代理实现的两种方式. 1. Spring AOP Spring是一个轻型容器,Spring整个系列的最最核心的概念当属IoC.AOP.可见AOP是Spring ...
- 一文带你搞懂C#多线程的5种写法
一文带你搞懂C#多线程的5种写法 1.简介 超长警告! 在学习本篇文章前你需要学习的相关知识: 线程基本知识 此篇文章简单总结了C#中主要的多线程实现方法,包括: Thread 线程 ThreadPo ...
- 一文多图搞定制作自己的VOC数据集+使用yolov4训练自己的数据集+封装video测试脚本(基于ubuntu)
一文多图搞定制作自己的VOC数据集+使用yolov4训练自己的数据集+封装video测试脚本(基于ubuntu) 制作VOC数据集 标注自己的数据集 整理数据集路径格式 训练数据集 环境 在Linux ...
- RPC框架:一文带你搞懂RPC
RPC是什么(GPT答) ChatGPT回答: RPC(Remote Procedure Call)是一种分布式应用程序的编程模型,允许程序在不同的计算机上运行.它以一种透明的方式,将一个程序的函数调 ...
- 一文多图搞懂KITTI数据集下载及解析
转载自一文多图搞懂KITTI数据集下载及解析-阿里云开发者社区 KITTI Dataset 1.图片下载:点击下载:https://s3.eu-central-1.amazonaws.com/avg- ...
- 渲染预览PDF文档,轻松搞定,这方案真香!
渲染预览PDF文档,轻松搞定,这方案真香! 1.前言 2.列举一些文档预览解决方案: 3.列举一些文档解析生成解决方案: 4.案列赏析 5.准备工作: 6.模板讲解: 7.代码实现: 8.效果图: 9 ...
- 【干货知识】Redis:从应用到底层,一文帮你搞定
1.基本类型及底层实现 1.1.String 用途: 适用于简单key-value存储.setnx key value实现分布式锁.计数器(原子性).分布式全局唯一ID. 底层:C语言中String用 ...
最新文章
- socket可以写成单例嘛_精读《设计模式 - Singleton 单例模式》
- 蒙特卡罗方法验证凯利公式
- CodeForces 474.D Flowers
- 【Nginx-20180108】Nginx的搭建文件服务器问题一则
- 如何在Java中将InputStream读取/转换为String?
- hql连接查询及外置命名查询
- QT4.7.3在dm6446平台上的移植[转]--make[1]: *** [assistant_cs.qm] Error 2
- cookie java 写入_JAVA中如何读写COOKIE
- [Usaco2011][bzoj2442][洛谷2527]修剪草坪解题报告(dp,贪心,单调队列)
- MYSQL中ALTER命令
- 深度 ghost linux系统,用Ghost实现Linux系统的备份
- 无法更改硬件兼容性时解决“虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本”的方法
- 《CSS权威指南》读书笔记4
- matlab中muw,matlab – 获取属于凸包的点
- C语言系列1——hello world
- thinkphp配置mysql集群_ThinkPHP教程_PHP框架之ThinkPHP(五)【连接数据库与主从数据库设置】...
- 5G混战:改变世界不需要论资排辈
- ubuntu设置时间为utc标准时间
- Python 第几周和星期几
- 安全加密 - HSM vs Trustzone vs SHE vs Evita ,