@Autowired 与@Resource的异同点

前言

最近写代码的时候,碰到一个小问题;
在这里插入图片描述
可以看到,Spring Boot不推荐使用@Autowired的方式进行属性注入。

我之前一直这样写,从来没觉得这有什么问题,看到这个报错,心里咯噔一下,然后忽然想,@Autowired 与@Resource有什么不同。

然后我发现,我竟然完全不记得了。

因此,写这篇笔记记录一下。

先解释一下,为什么Spring Boot不推荐使用@Autowired的方式进行属性注入。

  • @Autowired是spring定义的注解,与Spring框架强耦合,换成别的框架,可能不支持。
  • @Resource是JSR-250定义的注解,是Java标准,支持几乎所有java框架。

换言之,@Autowired能用的,@Resource也能用,@Autowired不能用的,@Resource还能用。

不过现在java程序员几乎等同于Spring程序员,说这个,似乎没有必要。

简单举例

LaymanController.java

@Controller
public class LaymanController {
    
    @Autowired
    public LaymanService laymanService;

    @GetMapping(value = "/sayHello")
    public void sayHello() {
         laymanService.sayHello();
    }
}

LaymanService

public interface LaymanService {
    void sayHello();
}

LaymanServiceImpl

@Service
public class LaymanServiceImpl implements LaymanService{
	public void sayHello(){
		System.out.println("你好,我是layman"); 
	}		
}

@Autowired

@Autowired默认按类型注入,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。

public @interface Autowired {
	# 注册时该类型必须存在,如果不存在则报错。
	boolean required() default true;
}

如果注入的类型有可能为null,可以这样配置:@Autowired(required = false)

言归正传,还是说下,下面这个例子的加载顺序:

	@Autowired
    public LaymanService laymanService;

项目启动后,由于我们在LaymanServiceImpl 上配置了@Service注解,那么它会被CompentScan扫描进容器内,注册为bean。

由于未指定name属性,使用默认值(类名首字母转小写)为bean命名(laymanServiceImpl

@Autowired查找类型为LaymanService 的bean,如果找不到,则找名称为laymanService的bean。

很明显,有类型为LaymanService 的bean,名为laymanServiceImpl(多态),注入成功!

在这里插入图片描述

做个小改动,让它报个错

此时我们再添加一个类,叫做LaymanServiceImpl2

LaymanServiceImpl2.java

@Service
public class LaymanServiceImpl2 implements LaymanService{
	public void sayHello(){
		System.out.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的装配顺序
  1. 既不指定name,也不指定type
    在这里插入图片描述

  2. 指定name

在这里插入图片描述

  1. 指定type
    在这里插入图片描述

  2. 同时指定name和type
    在这里插入图片描述

为什么不推荐使用@Autowired,可是依然那么人用
  • 历史遗留问题(以前就这一种方式,开发用习惯了,改不了。)
  • 省事,bean的名字不用写。(按类型匹配,只要扔个@service就行了),@resource要写@service("service_name"),否则就要两次查找,浪费性能。(@resource先找name,因为默认名不匹配,所以找不到,还会再找type,而@Autowired直接找type)

但是,架构设计考虑性能的话,推荐使用@resource

一是因为耦合度,契合大部份java框架。
二是写上@service("service_name"),访问速度会很快,毕竟可以通过name精准搜索。

缺点是,每个bean都要手动添加name属性。

补充

@AutowiredcommonAnnotationBeanPostProcessor处理器负责处理,而@ResourceautowiredAnnotationBeanPostProcessor处理器负责处理。

有兴趣的可以看看源码:

推荐的源码博客:https://blog.csdn.net/ijavaweb/article/details/25553231

  • 9
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
@Autowired与@Resource是用来实现依赖注入的注解,在Spring/Spring Boot项目中使用。它们具有一些不同之处。首先,它们的来源不同,@Autowired来自于Spring框架,而@Resource来自于Java的JSR-250。其次,它们依赖查找的顺序不同,@Autowired先根据类型再根据名称查询,而@Resource先根据名称再根据类型查询。另外,它们支持的参数数量和用法也有所不同。@Autowired只支持设置一个参数,而@Resource支持设置多达七个参数。关于依赖注入的用法支持,@Autowired既支持构造方法注入,又支持属性注入和Setter注入,而@Resource只支持属性注入和Setter注入。此外,在编译器IDEA中,当注入Mapper对象时,使用@Autowired注解编译器会提示错误,而使用@Resource注解则不会提示错误。需要注意的是,@Autowired是由Spring提供,而@Resource是由Java提供。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [面试突击:@Autowired 和 @Resource 有什么区别?你学会了吗?](https://blog.csdn.net/Candyz7/article/details/126578224)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [@Resource和@Autowired的区别与理解](https://blog.csdn.net/hanhanhanxu/article/details/106433857)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值