@Autowired:Spring 亲生的,默认按类型(Type)注入。

@Resource:JDK 自带的,默认按名称(Name)注入。

好问题!这个区别在刚从 PHP 转 Java 的时候确实容易迷糊。我用一个“点外卖”的例子给你讲透,再配上代码,你一看就懂。


核心比喻:去公司前台取快递

想象 Spring 容器是一个巨大的前台储物柜,里面放满了各种各样的 Bean(对象)。 你要取一个 IBrandService 的对象。

  • @Autowired(按类型): 你跟前台说:“给我拿一个 IBrandService 类型的家伙。”
  • @Resource(按名称): 你跟前台说:“给我拿那个贴着 brandServiceImpl 标签的家伙。”

场景复现:一个接口,一个实现类(最简单的情况)

这种情况下,两者没区别,都能用。

接口:

  1. public interface IBrandService {
  2. String getBrandName();
  3. }

实现类:

  1. @Service // 默认 Bean 的名字叫 brandServiceImpl
  2. public class BrandServiceImpl implements IBrandService {
  3. @Override
  4. public String getBrandName() {
  5. return "Toyota";
  6. }
  7. }

调用方:

  1. @Service
  2. public class CarServiceImpl implements ICarService {
  3. // 方式一:Autowired(按类型找)
  4. @Autowired
  5. private IBrandService brandService;
  6. // 方式二:Resource(按名字找)
  7. @Resource
  8. private IBrandService brandService;
  9. // 两者都能注入成功!
  10. }

👉 结果:都能拿到 BrandServiceImpl 的实例。


关键区别:一个接口,两个实现类(面试常考!)

这是最能体现区别的地方。假设我们有两个品牌的实现类。

两个实现类:

  1. @Service("toyotaService") // 指定 Bean 名为 toyotaService
  2. public class ToyotaServiceImpl implements IBrandService {
  3. @Override
  4. public String getBrandName() {
  5. return "Toyota";
  6. }
  7. }
  8. @Service("bmwService") // 指定 Bean 名为 bmwService
  9. public class BmwServiceImpl implements IBrandService {
  10. @Override
  11. public String getBrandName() {
  12. return "BMW";
  13. }
  14. }

现在储物柜里有两个 IBrandService 类型的对象了。

1. 使用 @Autowired(按类型)

  1. @Service
  2. public class CarServiceImpl implements ICarService {
  3. @Autowired
  4. private IBrandService brandService; // 报错!
  5. }

发生了什么? 你告诉 Spring:“给我拿一个 IBrandService 类型的家伙。” Spring 一看柜子,懵了:“这里面有两个啊(toyotaService 和 bmwService),你到底要哪个?” 于是 Spring 直接抛异常:NoUniqueBeanDefinitionException(没有唯一的 Bean 定义异常)。

怎么解决? 你需要配合 @Qualifier 指定名字,相当于告诉 Spring 具体要哪个:

  1. @Autowired
  2. @Qualifier("bmwService") // 明确指定要叫这个名字的
  3. private IBrandService brandService; // 成功拿到 BMW

2. 使用 @Resource(按名称)

  1. @Service
  2. public class CarServiceImpl implements ICarService {
  3. // 情况 A:直接指定名字
  4. @Resource(name = "toyotaService")
  5. private IBrandService brandService; // 成功拿到 Toyota
  6. // 情况 B:不指定名字,默认按变量名查找
  7. @Resource
  8. private IBrandService bmwService; // Spring 会去找名叫 "bmwService" 的 Bean
  9. // 正好匹配上了 BmwServiceImpl,成功!
  10. }

发生了什么? @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')

若依框架里的实战建议

  1. 如果你只有一个实现类:随便用,甚至可以直接用 Lombok 的构造器注入(现在 Java 圈更推崇这个)。
  2. 如果你有多个实现类(比如支付服务有支付宝、微信):
    • 用 @Resource(name="xxx") 最直观,一眼就能看出用的是哪个实现。
    • 或者坚持用 @Autowired + @Qualifier。
  3. 若依的习惯:若依代码生成器生成的代码通常用 @Autowired,但在处理复杂的策略模式(比如不同的审批流、不同的导出方式)时,你会经常看到 @Qualifier。

一句话记住:

@Autowired 认祖归宗(看类型),@Resource 对号入座(看名字)。

这样是不是清楚多了?😁