详细解读spring中的@Resource注解

 更新时间:2023年10月09日 10:29:38   作者:空无多有  
这篇文章主要介绍了详细解读spring中的@Resource注解,此注解来源于JSR规范(Java Specification Requests),其作用是找到依赖的组件注入到应用来,它利用了JNDI技术查找所需的资源,需要的朋友可以参考下

@Resource属性介绍

  • name:资源的JNDI名称。在spring的注入时,指定bean的唯一标识。
  • type:指定bean的类型。
  • lookup:引用指向的资源的名称。它可以使用全局JNDI名称链接到任何兼容的资源。
  • authenticationType:指定资源的身份验证类型。它只能为任何受支持类型的连接工厂的资源指定此选项,而不能为其他类型的资源指定此选项。
  • shareable:指定此资源是否可以在此组件和其他组件之间共享。
  • mappedName:指定资源的映射名称。
  • description:指定资源的描述。

@Resource 的装配规则

默认情况下,即所有属性都不指定,它默认按照byType的方式装配bean对象。

  • 如果指定了name,没有指定type,则采用byName。
  • 如果没有指定name,而是指定了type,则按照byType装配bean对象。
  • 当byName和byType都指定了,两个都会校验,如果找不到,或者找到多个(比如byName的方式找到了BeanA, ByType的方式找到了BeanB ) 这种情况也是不会成功的.

上述略显官方的味道的解释,相信不少人也是晕晕的 , 也对这个"默认值" 情况解释的不到位 , 下面来个灵魂总结.

灵魂总结

注意: !!! type和name的根本逻辑就是 type是划定一个范围 , 然后name 在其中选择一个 举个栗子:

  • 如果 type 只匹配了 一个 ( 1 ) , 那么成功装备结果 必然是 1 , 如果name只有找到了1 , 或者没有找到的情况下才会配置成功( 没有显示指定name值, 默认为变量名) , name如果在容器中找到了非1 的bean ,则会报类型错误
  • 如果type 匹配了 ( 1 , 2 , 3 ) 多个实例 , 那么name只有匹配到 其中一个,才会装配成功, 如果一个也匹配不到 , 则会报错 ,因为spring不知道到底要装配哪个实例
  • 如果type一个都没有匹配到,那就直接凉凉了 ,报错:No qualifying bean of type xxx 的错误, 即使name指定的值在容器中找到了符合条件的bean实例, 也会报 类型不符合的错误

先来看下@Resource的应用场景

@Resource的应用场景一般都是在装配的时候出现了多个符合条件的bean , 这时候用@Autowired注解自动装配就会出现了问题 . 此时就可以用@Resource注解类解决问题 . (@Qualifier + @Autowired 也可以实现, 这里主要说下@Resource注解) , 通常就是解决多态的问题.

代码演示

这里示例将@Resource 放在了类的属性上

首先有个HelloService接口:

package com.resource.service;
public interface HelloService {
    void sayHello();
}

两个实现类 , HelloServiceImpl1 和 HelloServiceImpl2 , 实现的sayHello()方法,分别在控制台打印出 hello one! , hello two! 如下:

package com.resource.service.impl;
@Component
public class HelloServiceImpl1 implements HelloService {
    public void sayHello() {
        System.out.println("hello one!");
    }
}
package com.resource.service.impl;
@Component
public class HelloServiceImpl2 implements HelloService {
    public void sayHello() {
        System.out.println("hello two!");
    }
}

业务类UseService 实现属性装配

package com.resource;
@Component
public class UseService {
    //@Qualifier("helloServiceImpl1")
    //@Autowired
    //private HelloService helloService;
    @Resource
    private HelloService helloServiceImpl;
    public void say(){
        helloServiceImpl.sayHello();
    }
}

测试类

    public static void main(String[] args) {
        //1.创建容器
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("com");
        //2.获取对象
        UseService useService = ac.getBean("useService", UseService.class);
        useService.say();
    }

默认情况

装配代码 其它代码不变

    @Resource
    private HelloService helloServiceImpl;
    public void say(){
        helloServiceImpl.sayHello();
    }

运行测试

这时候如果什么都不指定, 运行则会报错如下:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.resource.service.HelloService' available: expected single matching bean but found 2:helloServiceImpl1,helloServiceImpl2

分析

@Resource是用 ByType和ByName 来装配的, 如果没有显示的通过type属性和name属性指定 , “就会找其默认值” 在这个示例中type就是HelloService.class , 又因为其是接口, spring在容器中找到了其两个已经注入容器的实现类分别为 helloServiceImpl1 , helloServiceImpl2 这两个实例. (范围) 而name 也没有通过属性执行 , name默认值就是变量的名称 helloServiceImpl , 显然spring容器中是没有的. (后续会通过测试验证) 通过默认指定值得ByType和ByName 其结果就是得到了两个符合要求的实例 , 而name也没有完成在type后有多个实例的情况下 “选一个” . 所有会有上述的把报错信息.

byName (name默认属性名) 装配代码

其它代码不变

    @Resource(type = HelloServiceImpl1.class )
    private HelloService helloServiceImpl1;
    public void say(){
        helloServiceImpl1.sayHello();
    }

这个变化就是上个示例中将属性名从helloServiceImpl 改成了 helloServiceImpl1 .

运行测试

hello one!
Process finished with exit code 0

分析

这里同样byType后 有两个实例 helloServiceImpl1 , helloServiceImpl2 , 而name没有显示指定, 默认为变量名 helloServiceImpl1 , 也完成了选一个的任务, 进而装配成功!

byName (name显示指定) 装配代码

其它代码不变

    @Resource(name="helloServiceImpl2")
    private HelloService helloServiceImpl1;
    public void say(){
        helloServiceImpl1.sayHello();
    }

这个变化就是上个示例中 指定了name属性的值

运行测试

hello two!
Process finished with exit code 0

分析

可以看到属性名为helloServiceImpl1 , 显示指定的是helloServiceImpl2 , 即如果显示指定name的值得话就取该值, 相当于是对默认的变量名覆盖了(可以这样理解). 就是有显示指定就用显示指定的, 没有就用变量名. 结果输出hello two! 就是对的了.

byType 显示指定 装配代码

其它代码不变 , 装配改为显示指定type值,如下

    @Resource(type = HelloServiceImpl1.class )
    private HelloService helloServiceImpl1;
    public void say(){
        helloServiceImpl1.sayHello();
    }

这个变化就是上个示例中 指定了name属性的值

运行测试

hello one!
Process finished with exit code 0

分析

显示指定了type = HelloServiceImpl1.class , 也就范围就是 helloServiceImpl1 , 根据开头的灵魂总结 , type已经确定了一个 , 那么 name (默认变量名 或者显示指定 ) 的值 就必须是helloServiceImpl1 或者是一个在spring容器中找不到的名称.

注意: 这是个坑, 如果你指定的变量名刚好是spring容器中的某个bean的id , 那么这里就会报 Bean named ‘xxxx’ is expected to be of type ‘com.resource.service.impl.HelloServiceImpl1’ 的异常!!!

这里用代码演示下: 新建了个HiService类

package com.resource.service.impl;
@Component
public class HiService {
   public void sayHello() {
       System.out.println("Hi Hi!");
   }
}

装配类 (主要改了变量名为hiservice ,HiService 的bean id)

    @Resource(type = HelloServiceImpl1.class )
    private HelloService hiService;
    public void say(){
        hiService.sayHello();
    }

运行报类型的错误如下:

org.springframework.beans.factory.BeanNotOfRequiredTypeException:
 Bean named 'hiService' is expected to be of type 'com.resource.service.impl.HelloServiceImpl1' 
 but was actually of type 'com.resource.service.impl.HiService'

到此这篇关于详细解读spring中的@Resource注解的文章就介绍到这了,更多相关spring中的@Resource注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springmvc基于fastjson实现导包及配置文件

    Springmvc基于fastjson实现导包及配置文件

    这篇文章主要介绍了Springmvc基于fastjson实现导包及配置文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • 详解Java中CAS机制的原理与优缺点

    详解Java中CAS机制的原理与优缺点

    CAS 英文就是 compare and swap ,也就是比较并交换,这篇文章主要来和大家介绍一下Java中CAS机制的原理与优缺点,感兴趣的小伙伴可以了解一下
    2023-06-06
  • 解决swagger主页访问,返回报错500问题

    解决swagger主页访问,返回报错500问题

    在使用Swagger时遇到500错误,通过仔细的debug发现问题源于注解使用不当,具体表现为一个接口的入参被错误地注解了三个参数,而实际上只有两个,这导致了Swagger在解析时抛出了NullPointerException异常,解决方法是删除错误的第三个参数的注解
    2024-09-09
  • mac下修改idea的jvm运行参数解决idea卡顿的情况

    mac下修改idea的jvm运行参数解决idea卡顿的情况

    这篇文章主要介绍了mac下修改idea的jvm运行参数解决idea卡顿的情况,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java获取代码中方法参数名信息的方法

    Java获取代码中方法参数名信息的方法

    在java中,可以通过反射获取到类、字段、方法签名等相关的信息,像方法名、返回值类型、参数类型、泛型类型参数等,但是不能够获取方法的参数名。在实际开发场景中,有时需要根据方法的参数名做一些操作,那么该如何操作了呢?下面就通过这篇文章来学习学习吧。
    2016-09-09
  • Java工具类实现高效编写报表

    Java工具类实现高效编写报表

    对于报表数据大部分情况下使用写sql的方式为大屏/报表提供数据来源,但是对于某些复杂情况下仅仅使用sql无法实现,这篇文章主要介绍了Java工具类实现高效编写报表
    2022-11-11
  • Spring boot 数据源未配置异常的解决

    Spring boot 数据源未配置异常的解决

    这篇文章主要介绍了Spring boot 数据源未配置异常的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • SpringBoot 使用jwt进行身份验证的方法示例

    SpringBoot 使用jwt进行身份验证的方法示例

    这篇文章主要介绍了SpringBoot 使用jwt进行身份验证的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • 搞懂JAVAObject中的hashCode()

    搞懂JAVAObject中的hashCode()

    今天小编就为大家分享一篇关于关于Object中equals方法和hashCode方法判断的分析,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2021-08-08
  • java在原字符中插入新字符或字符串实例

    java在原字符中插入新字符或字符串实例

    这篇文章主要介绍了java在原字符中插入新字符或字符串实例,具有很好的价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08

最新评论