理解@Autowired和@Resource的作用,不同匹配规则原理

@Autowired@Resource都是用于Spring框架中实现依赖注入的注解,它们可以帮助我们自动地将Bean注入到需要的地方,减少硬编码的依赖。

下面我会通过代码示例详细解释它们的用途以及在不同匹配规则下的区别。


首先,我们先了解一下在依赖注入场景下类型和名称的含义。

在依赖注入的场景下,考虑一个简单的例子,假设我们正在构建一个音乐播放器应用,这个应用能够播放不同类型的音频文件。为了简化,我们关注播放MP3文件的功能。

// 定义一个播放器接口,这是类型
public interface AudioPlayer {
    void play();
}

// 实现MP3播放器,这也是一个类型,具体实现了AudioPlayer接口
@Service("mp3Player") // 注意这里的名称"mp3Player"
public class MP3Player implements AudioPlayer {
    @Override
    public void play() {
        System.out.println("Playing MP3 file");
    }
}

// 用户界面类,需要注入一个播放器来播放音乐
@Service
public class MusicUI {
    
    // 使用@Autowired按类型注入,但如果有多个类型匹配的Bean,需要额外指定名称
    @Autowired
    private AudioPlayer audioPlayer; // 这是类型
    
    // 或者使用@Resource按名称注入
    // @Resource(name = "mp3Player") // 这里是名称
    // private AudioPlayer audioPlayer;
    
    public void startPlaying() {
        audioPlayer.play();
    }
}

解释

  • 类型(Type):在上述代码中,AudioPlayer接口是一个类型,它定义了播放器应具备的播放功能。MP3Player类也是一个类型,因为它实现了AudioPlayer接口,是具体播放MP3文件的实现类。在MusicUI类中,字段audioPlayer声明为类型AudioPlayer,表明它期望注入任何实现了AudioPlayer接口的Bean。

  • 名称(Name):在MP3Player类的定义中,@Service("mp3Player")注解为这个Bean指定了名称"mp3Player"。这个名称是用来唯一标识Spring容器中这个具体Bean的标识符。如果我们在MusicUI类中使用@Resource(name = "mp3Player"),那么这里"mp3Player"就是我们通过名称指定的注入目标,明确告知Spring应该注入名称为"mp3Player"的Bean。

因此,在这个例子中,“类型”指的是接口AudioPlayer和其实现类MP3Player所代表的抽象和具体功能分类,而“名称”则是具体Bean实例在Spring容器中的唯一标识,如"mp3Player"。


@Autowired

@Autowired是Spring框架提供的注解,主要用于根据类型进行依赖注入。

如果存在多个相同类型的Bean,它会尝试按名称匹配(如果Bean的名称与字段或属性名称相同),或者需要使用@Qualifier来指定具体Bean的名称。

代码示例:

假设我们有以下两个实现类:

@Service
public class ServiceA implements MyService {}

@Service
public class ServiceB implements MyService {}

按类型注入:

@Service
public class ClientService {

    @Autowired
    private MyService myService; 
    // 默认情况下,如果只有一个MyService的实现,将按类型注入。
    //如果有多个实现,这里会报错,除非使用@Qualifier指定具体实现。
}

按名称注入(配合@Qualifier):

@Service
public class ClientService {

    @Autowired
    @Qualifier("ServiceA")
    private MyService myService; 
    // 明确指定注入ServiceA
}

@Resource

@Resource是Java EE规范的一部分,但Spring也支持使用它进行依赖注入。

它默认按照名称进行匹配,如果未指定名称,则使用字段名或setter方法名(去除set前缀)作为Bean的名称进行查找。如果找不到按名称匹配的Bean,它才会尝试按类型进行匹配。

代码示例:

假设我们有同样的ServiceAServiceB,但是使用@Resource进行注入:

按名称注入(默认):

@Service
public class ClientService {

    @Resource
    private MyService myService; 
    // 假设有一个Bean的名称为myService,将按名称注入。
    //如果没有按名称匹配的Bean,则尝试按类型注入。
}
  1. Bean的命名:如果在Spring容器中确实存在一个名称为myService的Bean,并且这个Bean是MyService接口的一个实现(比如ServiceAServiceB被命名为myService),那么@Resource将能够按名称成功注入这个Bean,不会报错。

  2. 类型兼容性:如果按名称没有找到匹配的Bean,@Resource会尝试按类型匹配。如果容器中只有一个实现了MyService接口的Bean,即使它没有匹配的名称,按类型匹配也能成功,也不会报错。

  3. 多个类型匹配的Bean:如果按名称没有匹配到Bean,且存在多个实现了MyService接口的Bean(如ServiceAServiceB),而没有明确指定名称,理论上这可能导致不确定的行为或错误,因为@Resource的文档并未明确指出在此种情况下会如何处理。
    但实际上,Spring在处理@Resource时,如果找不到按名称匹配的Bean,通常会尝试按类型匹配,并且如果存在多个类型匹配的Bean且没有进一步指示(如@Primary注解来标识首选Bean),在某些版本的Spring中可能会抛出异常,因为无法确定要注入哪个Bean。

指定名称注入:

@Service
public class ClientService {

    @Resource(name = "ServiceA")
    private MyService serviceA; 
    // 明确指定注入名为ServiceA的Bean
}

不同匹配规则的区别

  1. 默认匹配策略@Autowired默认按类型匹配,而@Resource默认按名称匹配。
  2. 名称匹配优先级@Resource更倾向于使用名称匹配,即使不显式指定name属性,它也会尝试使用字段名或setter方法名作为Bean名称。而@Autowired没有这样的默认行为,必须通过@Qualifier来指定名称。
  3. 灵活性@Autowired配合@Qualifier使用时,既可以实现按类型也可以实现按名称注入,提供了较高的灵活性。而@Resource虽然也可以指定name属性来改变默认行为,但其默认的按名称匹配逻辑在某些情况下可能更加直观。
  4. 兼容性@Resource因为是Java EE规范的一部分,所以在非Spring框架的Java EE环境中也能使用,具有更好的跨框架兼容性。

综上所述,选择@Autowired还是@Resource取决于具体的需求,包括是否需要跨框架兼容性、是否更倾向于名称匹配的直观性、以及对灵活性的需求等。

  • 25
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值