一文让您搞清楚@Resources, @Inject和@Autowired的区别
@TOC
本文简述这三个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; @Test public 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 { @Resource private File dependency1; @Resource private File dependency2; @Test public void givenResourceAnnotation_WhenField_ThenDependency1Valid(){ assertNotNull(dependency1); assertEquals("defaultFile.txt", dependency1.getName()); } @Test public 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 { @Inject private ArbitraryDependency fieldInjectDependency; @Test public 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 { @Inject private ArbitraryDependency defaultDependency; @Inject private ArbitraryDependency namedDependency; @Test public void givenInjectQualifier_WhenOnField_ThenDefaultFileValid(){ assertNotNull(defaultDependency); assertEquals("Arbitrary Dependency", defaultDependency.toString()); } @Test public 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; @Test public void givenInjectQualifier_WhenSetOnField_ThenDependencyValid(){ assertNotNull(yetAnotherFieldInjectDependency); assertEquals("Yet Another Arbitrary Dependency", yetAnotherFieldInjectDependency.toString()); } }
application context代码:
@Configuration public class ApplicationContextTestInjectName { @Bean public ArbitraryDependency yetAnotherFieldInjectDependency() { ArbitraryDependency yetAnotherFieldInjectDependency = new YetAnotherArbitraryDependency(); return yetAnotherFieldInjectDependency; } }
测试通过
@Autowired
这个注解和@Inject的用法一致,唯一区别就是@Autowired 属于Spring框架提供的注解。例子略。
本文来自云栖社区合作伙伴“汪子熙”,了解相关信息可以关注微信公众号"汪子熙"。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
iframe父页面跨域向子页面传递消息
使用H5的postMessage()方法 嵌入iframe的父页面 //指定iframe var iframe = document.getElementById("myiframe").contentWindow; //发送的消息 var msg = 1; //嵌入iframe的域名 var childDomain = "https://api.ehuier.com"; iframe.postMessage(msg, childDomain); iframe子页面 window.addEventListener('message', function (e) { //接收消息 if (e.data == 1) { 待执行逻辑 } }, false);
- 下一篇
别再用PS了,我用五行Python代码就实现了批量抠图
对于会PhotoShop的人来说,抠图是非常简单的操作了,有时候几秒钟就能扣好一张图。不过对于一些比较复杂的图,有时候还是需要花点时间的,今天就给大家带了一个非常快速简单的办法,用Python来批量抠取人像。 效果展示 刚开始,我也不看好什么自动抠图,总觉得不够精确,抠不出满意的图。下面我就直接展示一下效果图吧。 我们先看看原图 : 这张图片背景是纯色,我们平时用PhotoShop抠起来也比较简单,对我们计算机来说也不是什么难题,下面是效果图: 因为本身是PNG图片,而且原图是白色背景,所以看不出什么区别。为了显示效果,我把原图和抠好的图放到一张黄色背景图片上: 这样一看效果明显多了,感觉抠图效果还是非常好的。但是,抠这种简单的图片,不怎么过瘾,我们再来看看复杂一点的图片: 这张图片背景色比之前复杂一些,而且有渐变,我们来看看抠图后的效果如何: 这个原图背景不是白色,我就不弄黄色背景了,感觉这个效果也还算满意。 那么,对于多人物的图片,效果如何呢?我们再看看下面这张图片: 这里有三个人,我们看看程序能...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS关闭SELinux安全模块
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程