Spring中@RabbitHandler和@RabbitListener的区别详析

 更新时间:2024年02月20日 10:03:01   作者:来自宇宙的曹先生  
@RabbitHandler是用于处理消息的方法注解,它与@RabbitListener注解一起使用,这篇文章主要给大家介绍了关于Spring中@RabbitHandler和@RabbitListener区别的相关资料,需要的朋友可以参考下

@RabbitHandler 和 @RabbitListener 是Spring AMQP(特别是针对RabbitMQ)中常用的两个注解,它们在消息处理中扮演着不同的角色。

@RabbitListener

  • 定义@RabbitListener 注解用于标记一个方法,使其成为消息队列的监听器,即这个方法负责接收来自RabbitMQ的消息。

  • 使用场景:当你想让某个服务类中的方法直接监听某个RabbitMQ队列时,你会在该方法上使用 @RabbitListener

  • 功能

    • 它可以指定监听的队列、交换机和路由键。
    • 支持异步处理,可以处理发送到指定队列的消息。
    • 可以与Spring的 @Transactional 注解结合使用,以确保消息处理的事务性。

@RabbitHandler

  • 定义@RabbitHandler 注解用于标记一个方法,作为特定类型的消息的处理器。

  • 使用场景:在一个类中可能有多个不同的方法处理不同类型的消息。这时,你可以在这个类上使用 @RabbitListener,然后在每个处理方法上使用 @RabbitHandler,以便根据消息类型调用适当的方法。

  • 功能

    • 主要用于方法级别的多态,即在同一个类中根据消息的不同类型来调用不同的处理方法。
    • 允许你在同一个监听器类中定义多个处理不同类型消息的方法。

结合使用

  • 通常,@RabbitListener 用于类级别或方法级别,定义消息的入口点,即指定哪个队列的消息会被监听。
  • @RabbitHandler 则用于在同一类中的不同方法上,根据接收到的消息类型调用相应的方法。

示例

@Component
public class MyMessageListener {

    @RabbitListener(queues = "myQueue")
    public void process(String data) {
        // 处理字符串类型的消息
    }

    @RabbitListener(queues = "myQueue")
    @RabbitHandler
    public void process(MyCustomObject object) {
        // 处理 MyCustomObject 类型的消息
    }
}

在这个示例中,@RabbitListener 用于指定监听的队列,而 @RabbitHandler 用于区分不同类型的消息应由哪个方法处理。这种结构使得在同一个监听器类中可以方便地处理多种类型的消息。

更详细的例子来阐明 @RabbitListener 和 @RabbitHandler 在实际使用中的差异和结合方式。

示例 1:基本的 @RabbitListener 使用

假设有一个场景,你需要监听一个名为 ordersQueue 的RabbitMQ队列,并对收到的订单消息进行处理。

@Component
public class OrderService {

    @RabbitListener(queues = "ordersQueue")
    public void receiveOrder(String orderJson) {
        // 解析订单JSON数据
        Order order = parseOrder(orderJson);
        // 处理订单
        processOrder(order);
    }

    // ...其他方法,如parseOrder和processOrder
}

在这个例子中,@RabbitListener 直接应用于方法 receiveOrder,这意味着这个方法将监听 ordersQueue 队列,并处理所有接收到的消息。

示例 2:结合使用 @RabbitListener 和 @RabbitHandler

考虑一个稍微复杂的场景,其中一个服务需要处理两种类型的消息:文本消息和JSON格式的订单消息。

@Component
@RabbitListener(queues = "mixedMessagesQueue")
public class MixedMessageService {

    @RabbitHandler
    public void processTextMessage(String text) {
        // 处理文本消息
        System.out.println("Received text message: " + text);
    }

    @RabbitHandler
    public void processOrderMessage(Order order) {
        // 处理订单对象
        System.out.println("Received order: " + order);
    }

    // ...其他可能的方法
}

在这个例子中,@RabbitListener 注解应用于类级别,意味着这个类中的所有方法都会监听 mixedMessagesQueue 队列。@RabbitHandler 则用于区分不同的处理方法:processTextMessage 用于处理文本消息,而 processOrderMessage 用于处理订单对象。Spring会根据消息的类型自动选择合适的方法。

示例 3:使用 @RabbitListener 的多方法监听

在某些情况下,你可能希望在同一个类中,不同的方法监听不同的队列。

@Component
public class MultiQueueListener {

    @RabbitListener(queues = "textQueue")
    public void processTextMessage(String text) {
        // 处理来自textQueue的文本消息
    }

    @RabbitListener(queues = "ordersQueue")
    public void processOrder(Order order) {
        // 处理来自ordersQueue的订单消息
    }
}

这个例子展示了在同一个类中,不同的方法可以监听不同的队列。processTextMessage 监听 textQueue 队列,而 processOrder 监听 ordersQueue 队列。

这些例子展示了 @RabbitListener 和 @RabbitHandler 在不同场景下的应用方式,包括单独使用 @RabbitListener、将 @RabbitListener 与 @RabbitHandler 结合使用以及在同一个类中使用多个 @RabbitListener 注解来监听不同的队列。

附:@RabbitListener或@RabbitHandler使用出现死循环

异常1问题:为什么会找不到消费实现?

@RabbitListener 或 @RabbitHandler 配置出错

很大原因是取决于content_type 的配置和 方法的形参。

如果通过客户端放入队列中有个content_type为空的的消息,@RabbitListener只有形参为String 的Handler,是无法对应上消费实现的。
@RabbitHandler 没有使用可选参数isDefault

消费者找不到任何一个消费实现,就回去找isDefault = true 的 handler,类似一个兜底策略。

异常1问题:处理思路

使用Message 作为方法形参

尽量将@RabbitListener 放在类上, 使用@RabbitHandler(isDefault = true) 做兜底策略

异常1分析 :死循环分析

这是一种应用级别的死循环,消息找不到消费实现,一直重试直到找到消费实现。这种死循环原因是配置失误,要在源头避免,测试阶段就要消灭。【找到消除这种死循环的方法再来填坑】。另外一种必须处理的死循环是已经找到消费实现,但是在消费的过程中造成死循环,见异常2:

【异常2】:消费过程中抛出未捕获Exception

通常是业务逻辑导致的异常如NullPointerException,无脑的做法是try-catch,处理不当依旧会造成死循环。

异常2问题:try-catch后仍然会死循环

总结

到此这篇关于Spring中@RabbitHandler和@RabbitListener区别的文章就介绍到这了,更多相关@RabbitHandler和@RabbitListener区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重复读取配置文件的方法

    Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重复读取配置文

    这篇文章主要介绍了Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重复读取配置文件的方法,需要的朋友可以参考下
    2015-12-12
  • Spring实战之依赖关系注入之后的行为示例

    Spring实战之依赖关系注入之后的行为示例

    这篇文章主要介绍了Spring实战之依赖关系注入之后的行为,结合实例形式分析了Spring依赖关系注入之后的行为实现与使用相关操作技巧,需要的朋友可以参考下
    2019-11-11
  • Java调度线程池ScheduledThreadPoolExecutor不执行问题分析

    Java调度线程池ScheduledThreadPoolExecutor不执行问题分析

    最近项目上反馈某个重要的定时任务突然不执行了,很头疼,开发环境和测试环境都没有出现过这个问题。定时任务采用的是ScheduledThreadPoolExecutor,后来一看代码发现踩了一个大坑。本文就来和大家聊聊这次的踩坑记录与解决方法,需要的可以参考一下
    2023-03-03
  • Java后端返回PDF预览给前端的实现

    Java后端返回PDF预览给前端的实现

    前端要预览服务器PDF 可直接将要blob流返回给前端,即可用浏览器自带pdf预览功能打开,本文就来介绍一下如何实现,感兴趣的可以了解一下
    2023-09-09
  • Java中使用Closeable接口自动关闭资源详解

    Java中使用Closeable接口自动关闭资源详解

    这篇文章主要介绍了Java中使用Closeable接口自动关闭资源详解,Closeable接口继承于AutoCloseable,主要的作用就是自动的关闭资源,其中close()方法是关闭流并且释放与其相关的任何方法,如果流已被关闭,那么调用此方法没有效果,需要的朋友可以参考下
    2023-12-12
  • Spring Security实现验证码登录功能

    Spring Security实现验证码登录功能

    这篇文章主要介绍了Spring Security实现验证码登录功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Spring bean加载控制实现方法

    Spring bean加载控制实现方法

    很多时候我们需要根据不同的条件在容器中加载不同的Bean,或者根据不同的条件来选择是否在容器中加载某个Bean,这就是Bean的加载控制,一般我们可以通过编程式或注解式两种不同的方式来完成Bean的加载控制
    2022-12-12
  • 使用@Autowired注解有错误提示的解决

    使用@Autowired注解有错误提示的解决

    这篇文章主要介绍了使用@Autowired注解有错误提示的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Spring中Bean的生命周期使用解析

    Spring中Bean的生命周期使用解析

    这篇文章主要介绍了Spring中Bean的生命周期使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • 详解JAVA中的for-each循环与迭代

    详解JAVA中的for-each循环与迭代

    本文详解了JAVA中的for-each循环与迭代,是JS入门学习中的基础知识,也是java中的难点知识,需要的朋友可以参考下 。
    2016-10-10

最新评论