`
JerryWang_SAP
  • 浏览: 1031644 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

一文让您搞清楚@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呢?访问这个链接:jcp.org/en/jsr/detail?

里面有很多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里,文档链接:

jcp.org/en/jsr/detail?

注入的优先级:

  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的原创文章,请关注公众号"汪子熙":

0
0
分享到:
评论

相关推荐

    详解Spring依赖注入:@Autowired,@Resource和@Inject区别与实现原理

    Spring 依赖注入:@Autowired,@Resource 和@Inject 区别与实现原理 Spring 依赖注入是指在应用程序中将对象之间的依赖关系自动装配的过程。Spring 框架提供了多种依赖注入方式,包括 @Autowired、@Resource 和@...

    Spring@Autowired注解与自动装配.rar

    - 如果`@Autowired`和JSR 330的`@Inject`同时存在,Spring会优先考虑`@Autowired`。 ### 6. 总结 `@Autowired`注解是Spring框架中实现依赖注入的重要工具,它简化了bean之间的依赖关系管理,增强了代码的灵活性和可...

    学习Spring笔记_Annotation(注解)_Autowired_Qualifier

    除了`@Autowired`,Spring框架还提供了其他的依赖注入注解,如`@Resource`(主要用于JSR-250规范,基于名称的注入)和`@Inject`(JSR-330规范,基于类型和名称的注入)。这些注解在不同的场景下有不同的优势,开发者...

    Java-Spring各种依赖注入注解的区别.doc

    总结来说,@Autowired、@Inject和@Resource都是Spring进行依赖注入的手段,它们的主要区别在于默认匹配策略、异常处理和是否支持字段名匹配。选择哪种注解取决于具体需求,如是否需要灵活性、是否要求必须存在依赖...

    kotlin-inject:kotlin的依赖注入库

    【kotlin-inject:探索Kotlin的依赖注入库】 在软件开发中,依赖注入(Dependency Injection,简称DI)是一种设计模式,它可以帮助我们构建松耦合、可测试且易于维护的代码。Kotlin-inject是Kotlin社区为Kotlin语言...

    python-inject:Python依赖注入

    python注入 依赖注入是python的好方法。 不是Guice或Spring的港口。 主要特征 快速地。 线程安全的。 易于使用。... 不窃取类的构造函数。... 不要尝试管理您的应用程序对象图。... @ inject . autoparams () def ref

    关于spring boot中几种注入方法的一些个人看法

    @Autowired 的工作原理是,在启动 Spring IoC 时,容器自动装载了一个 AutowiredAnnotationBeanPostProcessor 后置处理器,当容器扫描到 @Autowired、@Resource 或 @Inject 时,就会在 IoC 容器自动查找需要的 bean...

    javax-inject-1.0-201002241208.jar.zip

    《Java注射框架——javax.inject详解》 在Java开发中,依赖注入(Dependency Injection,简称DI)是一种设计模式,它能够使代码...同时,javax.inject与Hibernate的整合,让数据访问层的管理也变得更加简洁和规范。

    spring-autowire.zip

    总的来说,Spring的@Autowired注解是实现依赖注入的重要工具,它让我们的代码更加简洁,易于测试和维护。在IDEA 2020这样的现代开发环境中,结合Spring 5的强大功能,我们可以轻松地创建和管理复杂的项目结构。通过...

    vue 解决provide和inject响应的问题

    官网上说provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。 provide: Object | () => Object(一个对象或返回一个对象的函数) inject...

    .javax.inject_1.0.0.jar

    例如,Spring框架中的`@Autowired`注解可以与`@Inject`互换使用。 使用依赖注入可以带来以下好处: 1. **解耦**:对象不再直接创建依赖,而是通过容器获取,减少了类之间的耦合。 2. **易于测试**:测试时,可以很...

    官方jar包javax-inject.jar

    【标题】"官方jar包javax-inject.jar"指的是Java编程语言中的一个官方发布的库文件,主要包含`javax.inject`包下的类和接口。这个jar包是Java依赖注入(Dependency Injection,简称DI)的一个实现,主要用于简化对象...

    在Nutz中使用Ioc-Annotation的入门教程

    这个文件可能包含了如何定义和使用注解的示例代码,通过阅读和运行这个例子,您可以更好地理解Nutz的Ioc机制。 总结来说,Nutz的Ioc-Annotation功能使得Java开发更加简洁和高效。通过注解,我们可以轻松地管理对象...

    VC代码 RT_INJECT (实用代码源)

    VC代码 RT_INJECT (实用代码源)VC代码 RT_INJECT (实用代码源)VC代码 RT_INJECT (实用代码源)VC代码 RT_INJECT (实用代码源)VC代码 RT_INJECT (实用代码源)VC代码 RT_INJECT (实用代码源)VC代码 RT_INJECT (实用代码...

    spring注解实现注入.zip

    `@Autowired`注解可以应用于字段、方法和构造器参数。当应用于字段时,Spring会在初始化bean时自动填充该字段;对于方法,Spring会在bean实例化后调用该方法进行注入;构造器参数则在创建bean实例时进行注入。使用`...

    Spring依赖注入——java项目中使用spring注解方式进行注入.rar

    2. 注解注入:在需要注入依赖的类中,使用`@Autowired`、`@Qualifier`、`@Resource`或`@Inject`等注解标记字段或方法。 3. 配置扫描:在Spring配置文件中,使用`<context:component-scan>`标签指定需要扫描的包,使...

    javax-inject.jar.zip

    在Java编程环境中,我们经常会遇到依赖管理的问题,特别是在使用各种框架和库时。"javax-inject.jar" 是一个专门用于解决此类问题的库,它包含了`javax.inject`包,这个包是Java注射注入(Dependency Injection,...

    Location IOS13驱动版本,包含inject.dmg和inject.dmg.signature两个文件

    总之,这个压缩包包含的“inject.dmg”和“inject.dmg.signature”文件是iOS 13系统定位服务驱动的更新,提供增强的定位功能和安全性。在使用时,用户需要验证签名以确保文件的合法性,并根据设备的当前iOS版本进行...

    InjectDLL_injectDll_

    Usage: injectdll.exe [process name] [dll path] [option number]option 1 - CreateRemoteThreadoption 2 - NtCreateThreadExoption 3 - RtlCreateUserThread

    Location IOS12.4驱动版本,包含inject.dmg和inject.dmg.signature两个文件

    在iOS系统中,Location服务...总之,"inject.dmg"和"inject.dmg.signature"在iOS 12.4的Location服务更新中扮演着关键角色,它们确保了定位驱动的正确安装和安全运行,为用户提供更加精确、安全和节能的位置服务体验。

Global site tag (gtag.js) - Google Analytics