@Autowired:Spring 亲生的,默认按类型(Type)注入。
@Resource:JDK 自带的,默认按名称(Name)注入。
好问题!这个区别在刚从 PHP 转 Java 的时候确实容易迷糊。我用一个“点外卖”的例子给你讲透,再配上代码,你一看就懂。
核心比喻:去公司前台取快递
想象 Spring 容器是一个巨大的前台储物柜,里面放满了各种各样的 Bean(对象)。
你要取一个 IBrandService 的对象。
@Autowired(按类型): 你跟前台说:“给我拿一个IBrandService类型的家伙。”@Resource(按名称): 你跟前台说:“给我拿那个贴着brandServiceImpl标签的家伙。”
场景复现:一个接口,一个实现类(最简单的情况)
这种情况下,两者没区别,都能用。
接口:
public interface IBrandService {String getBrandName();}
实现类:
@Service // 默认 Bean 的名字叫 brandServiceImplpublic class BrandServiceImpl implements IBrandService {@Overridepublic String getBrandName() {return "Toyota";}}
调用方:
@Servicepublic class CarServiceImpl implements ICarService {// 方式一:Autowired(按类型找)@Autowiredprivate IBrandService brandService;// 方式二:Resource(按名字找)@Resourceprivate IBrandService brandService;// 两者都能注入成功!}
👉 结果:都能拿到 BrandServiceImpl 的实例。
关键区别:一个接口,两个实现类(面试常考!)
这是最能体现区别的地方。假设我们有两个品牌的实现类。
两个实现类:
@Service("toyotaService") // 指定 Bean 名为 toyotaServicepublic class ToyotaServiceImpl implements IBrandService {@Overridepublic String getBrandName() {return "Toyota";}}@Service("bmwService") // 指定 Bean 名为 bmwServicepublic class BmwServiceImpl implements IBrandService {@Overridepublic String getBrandName() {return "BMW";}}
现在储物柜里有两个 IBrandService 类型的对象了。
1. 使用 @Autowired(按类型)
@Servicepublic class CarServiceImpl implements ICarService {@Autowiredprivate IBrandService brandService; // 报错!}
发生了什么?
你告诉 Spring:“给我拿一个 IBrandService 类型的家伙。”
Spring 一看柜子,懵了:“这里面有两个啊(toyotaService 和 bmwService),你到底要哪个?”
于是 Spring 直接抛异常:NoUniqueBeanDefinitionException(没有唯一的 Bean 定义异常)。
怎么解决?
你需要配合 @Qualifier 指定名字,相当于告诉 Spring 具体要哪个:
@Autowired@Qualifier("bmwService") // 明确指定要叫这个名字的private IBrandService brandService; // 成功拿到 BMW
2. 使用 @Resource(按名称)
@Servicepublic class CarServiceImpl implements ICarService {// 情况 A:直接指定名字@Resource(name = "toyotaService")private IBrandService brandService; // 成功拿到 Toyota// 情况 B:不指定名字,默认按变量名查找@Resourceprivate IBrandService bmwService; // Spring 会去找名叫 "bmwService" 的 Bean// 正好匹配上了 BmwServiceImpl,成功!}
发生了什么?
@Resource 很聪明,它先看你有没有写 name 属性。
- 写了:精准打击,拿指定的。
- 没写:它看你变量名叫啥(这里是
bmwService),去柜子里找贴着bmwService标签的对象。
总结对照表(给 PHP 老司机的速查表)
| 特性 | @Autowired |
@Resource |
|---|---|---|
| 来源 | Spring 亲生的 | JDK 自带的(JSR-250规范) |
| 默认查找方式 | By Type(按类型) | By Name(按名称) |
| 遇到多个实现类 | 报错,需配合 @Qualifier |
自动匹配变量名,或通过 name 指定 |
支持 @Primary |
支持(谁加了 @Primary 就优先注入谁) |
不支持 |
| 类比 PHP (Laravel) | $this->app->make(IBrandService::class) |
$this->app->get('brandServiceImpl') |
若依框架里的实战建议
- 如果你只有一个实现类:随便用,甚至可以直接用
Lombok的构造器注入(现在 Java 圈更推崇这个)。 - 如果你有多个实现类(比如支付服务有支付宝、微信):
- 用
@Resource(name="xxx")最直观,一眼就能看出用的是哪个实现。 - 或者坚持用
@Autowired + @Qualifier。
- 用
- 若依的习惯:若依代码生成器生成的代码通常用
@Autowired,但在处理复杂的策略模式(比如不同的审批流、不同的导出方式)时,你会经常看到@Qualifier。
一句话记住:
@Autowired认祖归宗(看类型),@Resource对号入座(看名字)。
这样是不是清楚多了?😁
