关于@Autowired和@Resource的实际测试(没时间就直接看结论),帮你认识他们的实际注入情况

本文详细探讨了Spring中@Autowired和@Resource注解的使用情况,包括当有多个实现类时如何选择注入。@Autowired默认按类型注入,多个实现时会尝试按变量名匹配;@Resource则在多个实现时会报错,除非指定name属性。文章建议避免如张三般的错误实践,推荐使用构造方法注入以确保组件在创建时即初始化完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

增加更新内容

2022-02-25
1.直接暴露结论在文首(喜欢看故事的就往下把过程看完,没时间的就看看结论)
2.结尾处更新spring官方推荐注入方式

言归正题,今天在百忙之中抽空测试了一个天天都在用,却又可能出现一些意外结果的玩意儿!@Autowired,很早之前就有人说过byType和byName注入之类的概念,但是有些东西你不亲自尝试,可能都不知道或许有些内容已经超乎了你的认识。废话不多说,使用的是springboot2.6.2,上测试结果!

结论

使用@Autowired
日常使用的@Autowired在注入实现类只有一个,直接帮你注入了!
但实现类有多个时,spring就不知道你到底想干嘛,不知道注入哪个了。会根据变量名去找一下试试
1.如果名字没有匹配,sorry,罢工;
2.如果名字能匹配上,帮你注入容器!

使用@Resource
日常使用的@Resource在注入实现类只有一个,直接帮你注入了!启动和调用都非常ok
但要注入的接口TestService有多个实现类时,spring就不知道你到底想干嘛,不知道注入哪个了,会根据变量名去找一下试试
1.如果名字没有匹配上类名(这里加个注释①,什么叫匹配上类名),sorry,启动都报错啊兄dei;
2.如果名字能匹配上,帮你注入容器!启动调用都ok
3.这里注意!!如果@Resource属性加了值(这里加个注释②,代码举例说明),比如@Resource(name = “testServiceImpl”),效果等同于第2点,名字能匹配上,帮你注入容器!启动调用都ok

一、正常情况

通常我们在使用的时候,定义的service接口可能只有一个实现类:
在这里插入图片描述
结构和图上一毛一样,此时我们controller层中注入TestService毫无问题:
在这里插入图片描述
无论是启动还是调用,非常的ok

1.只用@Autowired

场景1

那么我们现在有个小笨蛋(不知道是谁,就假设张三吧),写了这样一个代码:
在这里插入图片描述
诶?testService少了一个“t”,小笨蛋把名字写错了!
不过他没发现。
结果:
可以正常注入,也可以正常调用。

场景2

好,事来了,出现了一个新的业务,张三疯狂设计了一波,决定使用两个实现类去实现了这个Service接口,于是现在的结构如下:
在这里插入图片描述
别忘了,憨憨张三的testService还少了个“t”
在这里插入图片描述
在这里插入图片描述
张三激动万分,裤子都脱了,上去就启动项目!
在这里插入图片描述
哟!报错了!
没错,结果就是spring被张三整蒙了,你给我两个实现类,鬼知道你要用哪个?
结果:
启动报错

场景3

张三赶紧提上裤子找咋回事!但他不想百度,就想自己yy,他只认识@Autowired
经过一波努力后
哦~发现是不是因为自己傻乎乎名字没定义好
在这里插入图片描述
他就改了:
在这里插入图片描述
嘴里念咒语:“成功吧!!!阿巴阿巴阿巴!”
在这里插入图片描述

结果:
启动失败

场景4

哭泣的张三继续yy,他在想是不是得改改名字啥的,就改了一波:
在这里插入图片描述
“阿巴阿巴阿巴!!!”
结果:
启动成功!并且调用成功!调用的正是TestServiceImpl中的test方法

场景5

张三感觉自己练到了99级似的,似乎发现了真理,他改了一下名字:
在这里插入图片描述
继续 “阿巴阿巴阿巴!!!”
结果:
启动成功!并且调用成功!调用的正是TestServiceForOtherImpl中的test方法

Autowired结论:

没错,到这里你发现了么?
日常使用的@Autowired在注入实现类只有一个,直接帮你注入了!
但实现类有多个时,spring就不知道你到底想干嘛,不知道注入哪个了。会根据变量名去找一下试试
1.如果名字没有匹配,sorry,罢工;
2.如果名字能匹配上,帮你注入容器!

2023-02-04补充+修正结论

这个结论也是不断学习了解,通过看到别人翻阅源码的基础上,对上述结论的进一步完善
3.Autowired首先是byType寻找实现类,出现多个的时候,会经历一系列筛选(isAutowiredCandidate?是否符合Qualifier?是否是primary?),筛选完毕后还存在多个,则根据名称进行匹配!

2023-02-07补充图解
在这里插入图片描述

2023-03-23补充

byType是怎么匹配的呢?spring底层里有一个k,v的map集合。k是类名,v是spring存储容器的bean name名,也就是根据类名找name,然后再通过name获取到bean,本质还是通过name拿到bean的!

2.只用@Resource

还想听故事?做个人吧,动动手试一下不香么?
直接上结论!

日常使用的@Resource在注入实现类只有一个,直接帮你注入了!启动和调用都非常ok
但要注入的接口TestService有多个实现类时,spring就不知道你到底想干嘛,不知道注入哪个了,会根据变量名去找一下试试
1.如果名字没有匹配上类名(这里加个注释①,什么叫匹配上类名),sorry,启动都报错啊兄dei;
2.如果名字能匹配上,帮你注入容器!启动调用都ok
3.这里注意!!如果@Resource属性加了值(这里加个注释②,代码举例说明),比如@Resource(name = “testServiceImpl”),效果等同于第2点,名字能匹配上,帮你注入容器!启动调用都ok

注释①:
在这里插入图片描述
在这里插入图片描述
注释②:
在这里插入图片描述

特殊场景!!

张三强大的学习能力,自以为懂了这些注入,但有一天!张三不知道咋的,写了这样一个类:
在这里插入图片描述
今天,张三喝了几斤酒,就是要这样写!
启动!
控制台:
在这里插入图片描述
???啥情况!?不服,紧接着就试了一下@Autowired+@Qualifier(value = “aTestServiceImpl”) 或者@Resource(name = “aTestServiceImpl”)

哦对了,@Autowired+@Qualifier(value = “aTestServiceImpl”) 也是告诉了spring选出匹配的对象

结果发现咋的都不行,这是咋回事呢?!

其实,这是一种特殊情况,定义的类首字母和第二个字母都是大写,注入的方式就需要用一模一样的类名了!
在这里插入图片描述
@Autowired也是一样
在这里插入图片描述

二、不要学张三!!!

我们真实的工作中,尽量不要用这种方式:
在这里插入图片描述
我们考虑到,假设有一天,TestServiceImpl不用了,删了,或者改名字了,那代码中引用的属性名全都要改。。。(额就是test方法中引用的,上方图中未圈红色)

建议方式:
在这里插入图片描述
上图这种就只改圈红色的一处

或者
在这里插入图片描述
也是只需要改圈中的一处

三、Spring官方推荐构造方法注入

1.Controller层:

@RestController
@RequestMapping("/test")
public class TestForMe {

    private final TestForMeService testForMeService;

    public TestForMe(TestForMeService testForMeService) {
        this.testForMeService = testForMeService;
    }
    @RequestMapping("/testMethod")
    public void test(){
        testForMeService.test();
    }
}

2.Service层:

public interface TestForMeService {
    void test();
}
@Service
public class TestForMeServiceImpl implements TestForMeService {

    @Override
    public void test() {
        System.out.println("testService");
    }
}

其实主要看Contorller层注入testForMeService

	private final TestForMeService testForMeService;

    public TestForMe(TestForMeService testForMeService) {
        this.testForMeService = testForMeService;
    }

优势:
Spring文档:

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.

Spring 团队提倡使用基于构造方法的注入,因为这样一方面可以将依赖注入到一个不可变的变量中 (注:final 修饰的变量),另一方面也可以保证这些变量的值不会是 null。此外,经过构造方法完成依赖注入的组件 (注:比如各个 service),在被调用时可以保证它们都完全准备好了
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值