首页 > 其他分享 >Spring Boot中使用RabbitMQ完成延迟功能

Spring Boot中使用RabbitMQ完成延迟功能

时间:2023-11-09 18:13:28浏览次数:33  
标签:return 队列 Spring 绑定 Boot RabbitMQ 消息 public 路由

MQ-消息队列简单来说就是将“消息”放到“队列”中,然后慢慢处理队列中的消息。
完成延迟功能总体的思路是将消息放到队列中,为消息设置过期时间,不直接处理这个队列中的消息,
等到消息过期,将它转到另一个队列进行处理,从而完成延迟功能。

基本概念

1. 队列

队列是RabbitMQ的内部对象,用来存储消息。多个消费者可以订阅同一个队列。

2. 死信队列

消息变成死信的几种情况:
1. 消息被拒绝,并且requeue为false。
2. 消息过期
3. 队列达到最大长度
这里采取第二种方式,设置过期时间。

3. 交换器

交换器常用类型: direct、topic、fanout、headers。
路由键和队列之间的匹配规则取决于交换机的类型。

  1. 对于 direct 交换机:

    • 当一个队列通过绑定键(binding key)与 direct 交换机绑定时,只有消息的路由键与绑定键完全匹配时,消息才会被路由到该队列。
  2. 对于 fanout 交换机:

    • fanout 交换机会将消息广播给所有与之绑定的队列,忽略消息的路由键。
  3. 对于 topic 交换机:

    • topic 交换机使用通配符匹配路由键和绑定键之间的关系。
    • 路由键可以包含一个或多个单词(以点分隔),例如 "stock.usd.nyse"。
    • 绑定键可以使用以下通配符进行匹配:
      • *:匹配一个单词。
      • #:匹配零个或多个单词。
    • 例如,绑定键 "stock.*.nyse" 可以匹配 "stock.usd.nyse",但不匹配 "stock.eur.nyse"。
  4. 对于 headers 交换机:

    • headers 交换机使用消息的头部信息来匹配队列。
    • 消息的头部信息是一组键值对。
    • 当消息的头部信息与队列绑定时指定的键值对完全匹配时,消息才会被路由到该队列。

根据交换机类型和绑定规则,RabbitMQ 可以灵活地将消息路由到与之匹配的队列中。根据实际需求,我们可以选择合适的交换机类型和绑定规则来实现灵活的消息路由。

绑定

RabbitMQ通过绑定将消息路由到指定队列,Binding的作用是将交换器和队列关联起来。

代码

添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

配置

@Configuration
public class RabbitMQConfig {
    /**
     * orderQueue是正常的队列,用于接收实时信息
     * @return Queue
     */
    @Bean
    public Queue orderQueue() {
        return new Queue("orderQueue");
    }

    /**
     * orderDelayQueue是延迟队列,用于接收延迟信息
     * @return Queue
     */
    @Bean
    public Queue orderDelayQueue() {
        HashMap<String, Object> args = new HashMap<>();
        // 通过x-dead-letter-exchange设置为死信队列
        args.put("x-dead-letter-exchange", "");
        // 设置死信路由键,死信会被路由到orderQueue中
        args.put("x-dead-letter-routing-key", "orderQueue");
        // 设置消息过期时间,单位毫秒
        args.put("x-message-ttl", 60000);
        return new Queue("orderDelayQueue", true, false, false, args);
    }

    @Bean
    public DirectExchange orderExchange() {
        return new DirectExchange("orderExchange");
    }

    @Bean
    public Binding orderBinding() {
        return BindingBuilder.bind(orderQueue()).to(orderExchange()).with("orderRoutingKey");
    }

    @Bean
    public Binding orderDelayBinding() {
        return BindingBuilder.bind(orderDelayQueue()).to(orderExchange()).with("orderDelayRoutingKey");
    }
}

连接配置

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

发送消息

@Service
public class OrderService {
    private final RabbitTemplate rabbitTemplate;

    @Autowired
    public OrderService(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    public void sendOrder(String  params) {
        var id = "1";
        rabbitTemplate.convertAndSend("orderExchange", "orderRoutingKey", params, message -> {
            message.getMessageProperties().setMessageId(id);
            return message;
        });
    }

    public void sendDelayedOrder(Date pickUpTime, String param) {
        var id = "2";
        // 发送消息到orderDelayQueue队列中
        rabbitTemplate.convertAndSend("orderExchange", "orderDelayRoutingKey", param, message -> {
            // 设置消息过期时间,单位毫秒
            message.getMessageProperties().setExpiration(String.valueOf(getMilSecond(pickUpTime)));
            message.getMessageProperties().setMessageId(id);
            return message;
        });
    }

    public long getMilSecond(Date pickupTime) {
        long deliveryTime = pickupTime.getTime();
        // 计算过期时间的毫秒数
        return deliveryTime - System.currentTimeMillis();
    }
}

消费信息

@Service
public class RabbitMQService {
    @RabbitListener(queues = "orderQueue")
    public void deal1(String params, Channel channel, Message message) {
        System.out.println("orderQueue" + params);
    }

    @RabbitListener(queues = "orderQueue")
    public void deal2(String params, Channel channel, Message message) {
        System.out.println("orderQueue" + params);
    }

标签:return,队列,Spring,绑定,Boot,RabbitMQ,消息,public,路由
From: https://www.cnblogs.com/shames/p/17822450.html

相关文章

  • 强无敌!一个项目涵盖SpringBoot集成各种场景
    大家好,我是Java陈序员。我们都知道,作为Java后端开发肯定绕不开Spring,而SpringBoot的横空出世更是帮助我们开发者可以快速迭代一个项目!SpringBoot之所以强大,是因为支持自动化配置,可以快速装配组件,如持久化框架缓存消息队列日志等等。今天给大家介绍一个SpringBoot集成各种......
  • 第一次将Springboot项目上传到GitLab仓库(初始化)
    步骤:1、在GitLab上创建项目仓库(创建空项目)   创建完成如下: 2、在IDEA中新建一个Springboot项目 使用Git版本集成这里说明一下:1、本机计算机已经安装Git2、IDEA已经集成了Git3、这里使用的IDEA是2021版本(2018版本是VCS),IDEA中文......
  • Spring 缓存注解这样用,太香了!
    作者最近在开发公司项目时使用到Redis缓存,并在翻看前人代码时,看到了一种关于@Cacheable注解的自定义缓存有效期的解决方案,感觉比较实用,因此作者自己拓展完善了一番后分享给各位。Spring缓存常规配置SpringCache框架给我们提供了@Cacheable注解用于缓存方法返回内容。但......
  • Spring Boot:现代化Java应用开发的利器
    在当今的软件开发领域中,SpringBoot框架以其简洁、高效的特性成为了越来越多Java开发者的首选。本文将围绕SpringBoot框架展开讨论,深入探索其在现代化Java应用开发中的价值和影响。SpringBoot的背景与特点SpringBoot是由Pivotal团队创建的一个开源框架,它基于Spring框架,旨在简化S......
  • Spring RMI实现远程调用及源码
    1.RMI简单介绍Spring除了使用基于HTTP协议的远程调用方案,还为开发者提供了基于RMI机制的远程调用方法,RMI远程调用网络通信实现是基于TCP/IP协议完成的,而不是通过HTTP协议。在SpringRMI实现中,集成了标准的RMI-JRIM解决方案,该方案是java虚拟机实现的一部分,它使用java序列化来完成对......
  • No MyBatis mapper was found in ‘[SpringBoot启动类所在路径]‘ package 原因解析及
    NoMyBatismapperwasfoundin‘[SpringBoot启动类所在路径]‘package原因解析及解决方案NoMyBatismapperwasfoundin'[XXX]'package友情提示:搜到这篇文章的,一般是急于解决这个问题的,看下常见原因排除后,可以忽略分析过程直接看解决方案,我自己出现这个问题的原因主......
  • Spring与RMI集成实现远程访问
    暴露你的服务;在客户端,通过org.springframework.remoting.rmi.RmiProxyFactoryBean可以使用服务端暴露的服务,非常方便。这种C/S模型的访问方式,可以屏蔽掉RMI本身的复杂性,如服务端Skeleton和客户端Stub等的处理细节,这些对于服务开发和服务使用的人员来说,都是透明的,无需过度关注,而集中......
  • spring mvc 异常统一处理方式
    springmvc异常统一处理方式springMVC提供的异常处理主要有两种方式,一种是直接实现自己的HandlerExceptionResolver,另一种是使用注解的方式实现一个专门用于处理异常的Controller——ExceptionHandler。1、HandlerExceptionResolver:实现自己的HandlerExceptionResolver,Hand......
  • SpringMVC中Velocity的配置
    pom.xml所需velocity的jar<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>org.apache.ve......
  • Spring mvc中@RequestMapping 6个基本用法小结
    小结下springmvc中的@RequestMapping的用法。 1)最基本的,方法级别上应用,例如:    Java代码  @RequestMapping(value="/departments")public"simplePatternmethodwascalled");return"someResult";}  则访问http://loc......