zoukankan      html  css  js  c++  java
  • 一文让您搞清楚@Resources, @Inject和@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的注入按照如下的优先级进行:

    1. Match by Name
    2. Match by Type
    3. 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

    注入的优先级:

    1. Match by Type
    2. Match by Qualifier
    3. 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框架提供的注解。例子略。

    要获取更多Jerry的原创文章,请关注公众号"汪子熙":

  • 相关阅读:
    SharePoint 2016 图文安装教程
    CSS选择器的特殊性和LOVE HA
    CSS相邻兄弟选择器
    Javascript高级程序设计——函数
    Javascript高级程序设计——基本概念(二)
    Javascript高级程序设计——基本概念(一)
    Javascript高级程序设计——在HTML中使用Javascript
    Javascript高级程序设计——javascript简介
    Javascript包含对象的数组去重
    JQuery阻止表单提交的方法总结
  • 原文地址:https://www.cnblogs.com/sap-jerry/p/12734644.html
Copyright © 2011-2022 走看看