@Resource详解-代码⽰例
@Resource注解详解
此注解来源于JSR规范(Java Specification Requests),其作⽤是到依赖的组件注⼊到应⽤来,它利⽤了JNDI(Java Naming and Directory Interface Java命名⽬录接⼝ J2EE规范之⼀)技术查所需的资源。
⽹上查了些资料看的有点晕晕, 这⾥⽤例⼦来说明 @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;
public interface HelloService {
void sayHello();
}
两个实现类 , HelloServiceImpl1 和 HelloServiceImpl2 , 实现的sayHello()⽅法,分别在控制台打印出 hello one! , hello two! 如下:
package;
@Component
public class HelloServiceImpl1 implements HelloService {
public void sayHello(){
System.out.println("hello one!");
}
}
package;
@Component
public class HelloServiceImpl2 implements HelloService {
public void sayHello(){
System.out.println("hello two!");
}
}
业务类UseService 实现属性装配
package;
@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();
}
默认情况
装配代码
其它代码不变
private HelloService helloServiceImpl;
public void say(){
helloServiceImpl.sayHello();
}
resource和autowired注解的区别运⾏测试
这时候如果什么都不指定, 运⾏则会报错如下:
Caused by:NoUniqueBeanDefinitionException
: No qualifying bean of type 'source.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
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 , 根据开头的灵魂总结 , t
ype已经确定了⼀个 , 那么name (默认变量名 或者显⽰指定 ) 的值 就必须是helloServiceImpl1 或者是⼀个在spring容器中不到的名称.
注意: 这是个坑, 如果你指定的变量名刚好是spring容器中的某个bean的id , 那么这⾥就会报
Bean named ‘xxxx’ is expected to be of type ‘source.service.impl.HelloServiceImpl1’ 的异常
这⾥⽤代码演⽰下:
新建了个HiService类
package;
@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 'source.service.impl.HelloServiceImpl1'
but was actually of type 'source.service.impl.HiService'
finally
以上仅为个⼈见解 , 能看到这⾥希望能让您有所收获.
抛砖引⽟ , 如有不到之处, 敬请指正.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论