@Autowired和@Resource的异同
前言
最近写代码的时候,遇到了一个小问题;
可以看出,Spring Boot不建议使用@Autowired进行属性注入。
我以前也是这样写的,从来没觉得有什么不对。看到这个错误,我咯噔一下,然后突然想,@Autowired和@Resource有什么区别?
然后我发现我完全记不住了。
因此,写下这张纸条来记录它。
解释为什么Spring Boot不建议使用@Autowired进行属性注入。
@Autowired是spring定义的注释,与Spring框架强耦合,如果换成其他框架可能不支持。
@Resource是JSR-250定义的一个注释,它是一个支持几乎所有spring mvc的Java标准。
换句话说,@Autowired工作,@Resource工作,@Autowired不工作,@Resource仍然工作。
但是现在java程序员几乎和Spring程序员平起平坐,所以这样说似乎没有必要。
简单举例
LaymanController.java
@控制器
公共类LaymanController(
@自动连线
公共LaymanService laymanService
@GetMapping(值='/sayHello ')
public void SayHello(){ 0
laymanservice . SayHello();
}
}
LaymanService
公共接口LaymanService {
void SayHello();
}
LaymanServiceImpl
@服务
公共类LaymanServiceImpl实现LaymanService{
public void SayHello(){ 0
system . out . println(‘你好,我是外行’);
}
}
@Autowired
@Autowired是默认的按类型注入.默认情况下,它要求依赖对象必须存在。如果允许空值,其必需的属性可以设置为false。
公共@接口Autowired {
#注册时必须存在此类型。如果不存在,将报告错误。
boolean必选()默认值为true
}
如果注入类型可能为空,可以按如下方式配置:@Autowired(必选=false)
无论如何,让我们谈谈以下示例的加载顺序:
@自动连线
公共LaymanService laymanService
项目启动后,因为我们在LaymanServiceImpl上配置了@Service注释,它将被CompentScan扫描到容器中,并注册为bean。
因为没有指定name属性,所以用默认值(类名的第一个字母改为小写)命名bean(laymanServiceImpl)
@Autowired查找laymanService类型的bean,如果没有,则查找名为LaymanService的bean。
显然,有一个名为laymanServiceImpl(多态)的LaymanService类型的bean,注入成功了!
做个小改动,让它报个错
此时,我们添加另一个名为LaymanServiceImpl2的类。
LaymanServiceImpl2.java
@服务
公共类LaymanServiceImpl2实现LaymanService{
public void SayHello(){ 0
系统退出
.println("你好,我是layman2");
}
}
此时,IOC容器中,存在两个类型为LaymanService的bean,一个名为laymanServiceImpl
,另一个名为laymanServiceImpl2
。
那么,项目启动会报错,为什么
因为@Autowired
默认按类型匹配,而且只匹配一个
,现在找到两个,它不知道应该注入哪个
于是它纠结,迷茫,最后一咬牙,还是报错吧。
如何解决该BUG
使用@Qualifier
注解。
修改代码。
LaymanServiceImpl2改动如下:
@Service("laymanService")
public class LaymanServiceImpl2 implements LaymanService{
public void sayHello(){
System.out.println("你好,我是layman");
}
}
@Service("laymanService")
为LaymanServiceImpl2 指定bean的name属性
。
LaymanController.java 改动如下:
@Autowired
@Qualifier("laymanService")
public LaymanService laymanService;
@Autowired扫描到两个类型为LaymanService 的bean,但是@Qualifier指定了bean的名称,因此它会去查找名为laymanService的bean,找到一个,装配成功!
@Autowired加载顺序图
@Resource
@Resource默认按名称
进行装配,且有两个极其重要的属性:name和type
Spring将@Resource注解的name属性解析为bean的名字,type属性则解析为bean的类型。
逻辑
如果既不指定name,也不指定type,则按照Name进行装配(默认为变量名)
如果指定name,则从上下文中查找名称(id)唯一匹配
的bean进行装配,找不到则抛出异常
如果指定type,则从上下文中找到类型唯一匹配
的bean进行装配,找不到或者找到多个,抛出异常
如果同时指定name和type,则从Spring上下文中找到唯一匹配
的bean进行装配,找不到则抛出异常
// 默认查找名为laymanService的bean,如果找到唯一一个,则匹配,如果找不到,再按类型去查找
@Resource
public LaymanService laymanService;
@Resource的装配顺序
-
既不指定name,也不指定type
-
指定name
-
指定type
-
同时指定name和type
为什么不推荐使用@Autowired,可是依然那么人用
- 历史遗留问题(以前就这一种方式,开发用习惯了,改不了。)
- 省事,bean的名字不用写。(按类型匹配,只要扔个
@service
就行了),@resource要写@service("service_name")
,否则就要两次查找,浪费性能。(@resource先找name,因为默认名不匹配,所以找不到,还会再找type,而@Autowired直接找type)
但是,架构设计考虑性能的话,推荐使用@resource
。
一是因为耦合度,契合大部份java框架。
二是写上@service("service_name")
,访问速度会很快,毕竟可以通过name精准搜索。
缺点是,每个bean都要手动添加name属性。
补充
@Autowired
是commonAnnotationBeanPostProcessor
处理器负责处理,而@Resource
是autowiredAnnotationBeanPostProcessor
处理器负责处理。
有兴趣的可以看看源码:
推荐的源码博客:https://blog.csdn.net/ijavaweb/article/details/25553231
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/157193.html