springboot整合rabbitmq

安装rabbitmq

下载docker镜像

docker pull rabbitmq:3-management

启动容器

docker run --name rabbitmq -p 5672:5672 -p 15672:15672 -d rabbitmq:3-management

查看容器

浏览器打开控制页面http://192.168.31.128:15672/#/  ip修改为自己虚拟机的ip,默认账号密码都是guest

springboot整合

依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.6.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
            <version>2.6.10</version>
        </dependency>
    </dependencies>

配置

server:
  port: 8001
spring:
  rabbitmq:
    host: 192.168.31.128
    port: 5672
    username: guest
    password: guest
    virtual-host: /

Direct Exchange(直连交换机)

  • 将消息发送到绑定键(binding key)与消息的路由键(routing key)完全匹配的队列。
  • 可以理解为完全匹配模式。
  • 通常用于点对点的消息传递。

这边要想接受到消息路由键就必须完全一样

上代码

配置类

RabbitConfigDirect.java
package com.cyz.config.direct;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfigDirect {

    public static final String DIRECT_EXCHANGE = "cyz_direct_exchange";

    public static final String QUEUE_INFORM_EMAIL = "cyz_direct_queue_email";
    public static final String QUEUE_INFORM_SMS = "cyz_direct_queue_sms";

    /**
     * 通配符 * 表示一个单词 且必须出现
     * 通配符 # 表示任意个单词 可以不出现
     */
    public static final String ROUTING_KEY_EMAIL_DIRECT = "cyzEmail";
    public static final String ROUTING_KEY_SMS_DIRECT = "zxxEmail";

    //声明交换机
    @Bean(DIRECT_EXCHANGE)
    public Exchange directExchange() {
        //durable(true) 持久化,mq重启之后交换机还在
        return ExchangeBuilder.directExchange(DIRECT_EXCHANGE).durable(true).build();
    }

    @Bean(QUEUE_INFORM_EMAIL)
    public Queue queueInformEmail() {
        return new Queue(QUEUE_INFORM_EMAIL);
    }

    @Bean(QUEUE_INFORM_SMS)
    public Queue queueInformSms() {
        return new Queue(QUEUE_INFORM_SMS);
    }


    @Bean
    public Binding bingingEmailToDirect(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
                                        @Qualifier(DIRECT_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_DIRECT).noargs();
    }

    @Bean
    public Binding bingingSmsToDirect(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
                                     @Qualifier(DIRECT_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_SMS_DIRECT).noargs();
    }
}

消费者

MessageReceiverDirect.java
package com.cyz.config.direct;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MessageReceiverDirect {

    @RabbitListener(queues = RabbitConfigDirect.QUEUE_INFORM_EMAIL)
    public void receiveEmailMessage(String message) {
        System.out.println("cyz_direct_queue_email Received Email message: " + message);
    }


    @RabbitListener(queues = RabbitConfigDirect.QUEUE_INFORM_SMS)
    public void receiveSmsMessage(String message) {
        System.out.println("cyz_direct_queue_sms Received Sms message: " + message);
    }

}

生产者

MessageSenderDirect.java
package com.cyz.config.direct;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessageSenderDirect {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    public void sendEmailMessage() {
        rabbitTemplate.convertAndSend(RabbitConfigDirect.DIRECT_EXCHANGE, "email", "email");
        rabbitTemplate.convertAndSend(RabbitConfigDirect.DIRECT_EXCHANGE, "cyzEmail", "cyzEmail");
        rabbitTemplate.convertAndSend(RabbitConfigDirect.DIRECT_EXCHANGE, "zxxEmail", "zxxEmail");
    }
}

测试

发送了三个,只收到了两个,所以直连的路由键必须一样才能匹配成功

Fanout Exchange(扇形交换机)

  • 将消息广播到所有绑定到该交换机上的队列。
  • 忽略消息的路由键,直接将消息发送给所有绑定的队列。
  • 通常用于一对多的消息广播。

扇形交换机会把所有的消息广播到与它绑定的所有队列,这边的路由键已经不起作用了

上代码

配置类

RabbitConfigFanout.java
package com.cyz.config.fanout;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfigFanout {

    public static final String FANOUT_EXCHANGE = "cyz_fanout_exchange";

    public static final String QUEUE_INFORM_EMAIL = "cyz_fanout_queue_email";
    public static final String QUEUE_INFORM_SMS = "cyz_fanout_queue_sms";

    /**
     * 通配符 * 表示一个单词 且必须出现
     * 通配符 # 表示任意个单词 可以不出现
     */
    public static final String ROUTING_KEY_EMAIL_FANOUT = "cyzEmail";
    public static final String ROUTING_KEY_SMS_FANOUT = "zxxEmail";

    //声明交换机
    @Bean(FANOUT_EXCHANGE)
    public Exchange directExchange() {
        //durable(true) 持久化,mq重启之后交换机还在
        return ExchangeBuilder.fanoutExchange(FANOUT_EXCHANGE).durable(true).build();
    }

    @Bean(QUEUE_INFORM_EMAIL)
    public Queue queueInformEmail() {
        return new Queue(QUEUE_INFORM_EMAIL);
    }

    @Bean(QUEUE_INFORM_SMS)
    public Queue queueInformSms() {
        return new Queue(QUEUE_INFORM_SMS);
    }


    @Bean
    public Binding bingingEmailToFanout(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
                                        @Qualifier(FANOUT_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_FANOUT).noargs();
    }

    @Bean
    public Binding bingingSmsToFanout(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
                                     @Qualifier(FANOUT_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_SMS_FANOUT).noargs();
    }
}

消费者

MessageReceiverFanout.java
package com.cyz.config.fanout;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MessageReceiverFanout {

    @RabbitListener(queues = RabbitConfigFanout.QUEUE_INFORM_EMAIL)
    public void receiveEmailMessage(String message) {
        System.out.println("cyz_fanout_queue_email Received Email message: " + message);
    }


    @RabbitListener(queues = RabbitConfigFanout.QUEUE_INFORM_SMS)
    public void receiveSmsMessage(String message) {
        System.out.println("cyz_fanout_queue_sms Received Sms message: " + message);
    }

}

生产者

MessageSenderFanout.java
package com.cyz.config.fanout;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessageSenderFanout {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendEmailMessage() {
        rabbitTemplate.convertAndSend(RabbitConfigFanout.FANOUT_EXCHANGE, "email", "email");
        rabbitTemplate.convertAndSend(RabbitConfigFanout.FANOUT_EXCHANGE, "cyzEmail", "cyzEmail");
        rabbitTemplate.convertAndSend(RabbitConfigFanout.FANOUT_EXCHANGE, "zxxEmail", "zxxEmail");
    }
}

测试

由结果可知,即使路由键不匹配也会收到消息

Topic Exchange(主题交换机)

  • 根据消息的路由键和绑定键之间的模式匹配规则,将消息发送到一个或多个符合条件的队列。
  • 绑定键可以使用通配符进行模式匹配。
  • 通常用于灵活的消息路由和订阅发布的场景。

这里通配符有两种:

一个是*(有且只有一个单词) 例如*.sms.*,匹配的字符串只可以类似aa.sms.bb类型的,像aa.aa.sms.bb、aa.sms.bb.bb、sms.aa、aa.sms等都不会匹配成功

  一个是#(可以匹配任意个单词,可以是零个单词) 例如#.sms.#,匹配的字符串只可以类似aa.sms.bb、aa.aa.sms.bb、aa.sms.bb.bb、sms.aa、aa.sms、sms等

上代码

配置类

RabbitConfigTopic.java
package com.cyz.config;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfigTopic {


    public static final String TOPIC_EXCHANGE = "cyz_topic_exchange";

    public static final String QUEUE_INFORM_EMAIL1 = "cyz_topic_queue_email1";
    public static final String QUEUE_INFORM_EMAIL2 = "cyz_topic_queue_email2";
    public static final String QUEUE_INFORM_SMS = "cyz_topic_queue_sms";

    /**
     * 通配符 * 表示一个单词 且必须出现
     * 通配符 # 表示任意个单词 可以不出现
     */
    public static final String ROUTING_KEY_EMAIL_TOPIC1 = "#.email.#";
    public static final String ROUTING_KEY_EMAIL_TOPIC2 = "*.email.*";
    public static final String ROUTING_KEY_SMS_TOPIC = "#.sms.#";

    //声明交换机
    @Bean(TOPIC_EXCHANGE)
    public Exchange topicExchange() {
        //durable(true) 持久化,mq重启之后交换机还在
        return ExchangeBuilder.topicExchange(TOPIC_EXCHANGE).durable(true).build();
    }

    @Bean(QUEUE_INFORM_EMAIL1)
    public Queue queueInformEmail1() {
        return new Queue(QUEUE_INFORM_EMAIL1);
    }

    @Bean(QUEUE_INFORM_EMAIL2)
    public Queue queueInformEmail2() {
        return new Queue(QUEUE_INFORM_EMAIL2);
    }

    @Bean(QUEUE_INFORM_SMS)
    public Queue queueInformSms() {
        return new Queue(QUEUE_INFORM_SMS);
    }

    @Bean
    public Binding bingingEmailToTopic1(@Qualifier(QUEUE_INFORM_EMAIL1) Queue queue,
                                        @Qualifier(TOPIC_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_TOPIC1).noargs();
    }

    @Bean
    public Binding bingingEmailToTopic2(@Qualifier(QUEUE_INFORM_EMAIL2) Queue queue,
                                        @Qualifier(TOPIC_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_EMAIL_TOPIC2).noargs();
    }

    @Bean
    public Binding bingingSmsToTopic(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
                                     @Qualifier(TOPIC_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY_SMS_TOPIC).noargs();
    }
}

消费者

MessageReceiverTopic.java
package com.cyz.config;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MessageReceiverTopic {

    @RabbitListener(queues = RabbitConfigTopic.QUEUE_INFORM_EMAIL1)
    public void receiveEmailMessage1(String message) {
        System.out.println("cyz_topic_queue_email1 Received Email message: " + message);
    }

    @RabbitListener(queues = RabbitConfigTopic.QUEUE_INFORM_EMAIL2)
    public void receiveEmailMessage2(String message) {
        System.out.println("cyz_topic_queue_email2 Received Email message: " + message);
    }

    @RabbitListener(queues = RabbitConfigTopic.QUEUE_INFORM_SMS)
    public void receiveSmsMessage(String message) {
        System.out.println("cyz_topic_queue_sms Received Sms message: " + message);
    }

}

生产者

MessageSenderTopic.java
package com.cyz.config;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessageSenderTopic {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendEmailMessage() {
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"email", "email");
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.email", "hello.email");
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"email.cyz", "email.cyz");
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.email.cyz", "hello.email.cyz");
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.email.cyz.zxx", "hello.email.cyz.zxx");
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"zxx.hello.email.cyz", "zxx.hello.email.cyz");
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"zxx.hello.email.cyz.zxx", "zxx.hello.email.cyz.zxx");
    }

    public void sendSmsMessage(String message) {
        rabbitTemplate.convertAndSend(RabbitConfigTopic.TOPIC_EXCHANGE,"hello.sms.cyz", message);
    }
}

测试

结果如下

又结果可知通配符的匹配规则,主题类型的交换机只要符合路由键规则就能匹配成功,接收到消息

Headers Exchange(头交换机)

  • 在消息头部的键值对进行匹配,根据匹配结果将消息发送给一个或多个队列。
  • 可以通过自定义规则进行复杂的匹配操作。
  • 通常用于消息头部信息匹配的场景。

只有指定情况下才可以匹配成功,例如Header里面必须有name且值为张三,那就只有消息中带有这个Header且值为张三的才能匹配,可以是多个值,必须全部匹配

上代码

配置类

RabbitConfigHeader.java
package com.cyz.config.header;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class RabbitConfigHeader {

    public static final String HEADER_EXCHANGE = "cyz_header_exchange";
    public static final String QUEUE_INFORM_EMAIL = "cyz_header_queue_email";


    //声明交换机
    @Bean(HEADER_EXCHANGE)
    public Exchange headerExchange() {
        return ExchangeBuilder.headersExchange(HEADER_EXCHANGE).durable(true).build();
    }

    @Bean(QUEUE_INFORM_EMAIL)
    public Queue queueInformEmail() {
        return new Queue(QUEUE_INFORM_EMAIL);
    }



    @Bean
    public Binding bingingEmailToHeader(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
                                        @Qualifier(HEADER_EXCHANGE) Exchange exchange) {
        Map<String, Object> headers = new HashMap<>();
        headers.put("name", "cyz");
        headers.put("age", "25");
        return BindingBuilder.bind(queue).to(exchange).with("").and(headers);
    }

}

消费者

MessageReceiverHeader.java
package com.cyz.config.header;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MessageReceiverHeader {

    @RabbitListener(queues = RabbitConfigHeader.QUEUE_INFORM_EMAIL)
    public void receiveEmailMessage(String message) {
        System.out.println("cyz_fanout_queue_email Received Email message: " + message);
    }

}

生产者

MessageSenderHeader.java
package com.cyz.config.header;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessageSenderHeader {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendEmailMessage() {
        String msg="hello1";
        MessageProperties messageProperties1 = new MessageProperties();
        messageProperties1.setHeader("name","cyz");
        messageProperties1.setHeader("age","25");
        Message message1 = new Message(msg.getBytes(),messageProperties1);
        rabbitTemplate.convertAndSend(RabbitConfigHeader.HEADER_EXCHANGE, null, message1);
        String msg2="hello2";
        MessageProperties messageProperties2 = new MessageProperties();
        messageProperties2.setHeader("name1","cyz");
        messageProperties2.setHeader("age","25");
        Message message2 = new Message(msg2.getBytes(),messageProperties2);
        rabbitTemplate.convertAndSend(RabbitConfigHeader.HEADER_EXCHANGE, null, message2);

        String msg3="hello3";
        MessageProperties messageProperties3 = new MessageProperties();
        messageProperties3.setHeader("name1","cyz");
        messageProperties3.setHeader("age1","25");
        Message message3 = new Message(msg3.getBytes(),messageProperties3);
        rabbitTemplate.convertAndSend(RabbitConfigHeader.HEADER_EXCHANGE, null, message3);

    }
}

测试

只匹配了一个

延时队列

消息延时

public class RabbitConfig_SLA {
    /**
     * 处理sla交换机名称
     */
    public final static String EXCHANGE_SLA_NAME = "tt_sla_task_exchange";
    /**
     * 处理过期任务队列
     */
    public final static String SLA_EXPIRE_TASK_QUEUE_NAME = "tt_sla_expire_task_queue";
    /**
     * 处理超时任务队列名称
     */
    public final static String SLA_TIMEOUT_TASK_QUEUE_NAME = "tt_sla_timeout_task_queue";
    /**
     * 过期路由
     */
    public final static String SLA_EXPIRE_TASK_KEY = "tt_sla_expire_task_key";
    /**
     * 超时路由
     */
    public final static String SLA_TIMEOUT_TASK_KEY = "tt_sla_timeout_task_key";

    @Bean(SLA_EXPIRE_TASK_QUEUE_NAME)
    public Queue expireQueue() {
        return QueueBuilder.durable(SLA_EXPIRE_TASK_QUEUE_NAME).build();
    }

    @Bean(SLA_TIMEOUT_TASK_QUEUE_NAME)
    public Queue timeoutQueue() {
        return QueueBuilder.durable(SLA_TIMEOUT_TASK_QUEUE_NAME).build();
    }

    @Bean(EXCHANGE_SLA_NAME)
    public Exchange exchange() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange(EXCHANGE_SLA_NAME, "x-delayed-message", true, false, args);
    }

    @Bean
    public Binding bindingExpire(@Qualifier(SLA_EXPIRE_TASK_QUEUE_NAME) Queue queue, @Qualifier(EXCHANGE_SLA_NAME) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(SLA_EXPIRE_TASK_KEY).noargs();
    }

    @Bean
    public Binding bindingTimeout(@Qualifier(SLA_TIMEOUT_TASK_QUEUE_NAME) Queue queue, @Qualifier(EXCHANGE_SLA_NAME) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(SLA_TIMEOUT_TASK_KEY).noargs();
    }

}
private Message buildMessage(SendMsgTemplate sendMsgTemplate, long time) {
        int delayTime = (int) (time - System.currentTimeMillis());
        if (delayTime < 0) {
            delayTime = 0;
        }
        Message message = new Message(JSONObject.toJSONString(sendMsgTemplate).getBytes());
        message.getMessageProperties().setDelay(delayTime);
        return message;
    }

public void sendSlaExpireMq(SendMsgTemplate sendMsgTemplate) {
        log.info("enter sendSlaExpireMq {}", sendMsgTemplate);
        rabbitTemplate.convertAndSend(RabbitConfig_SLA.EXCHANGE_SLA_NAME, RabbitConfig_SLA.SLA_EXPIRE_TASK_KEY, buildMessage(sendMsgTemplate, sendMsgTemplate.getExpireTime()));
        log.info("finish sendSlaExpireMq {}", sendMsgTemplate);
    }

死信队列

创建两个队列和两个交换机如下,通过死信队列实现延时队列功能

上代码

配置类

RabbitConfigDelay.java
package com.cyz.config.delayqueue;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Configuration
public class RabbitConfigDelay {

    public static final String DELAY_EXCHANGE = "cyz_delay_exchange";
    public static final String NORMAL_EXCHANGE = "cyz_normal_exchange";

    public static final String DELAY_QUEUE = "cyz_delay_queue";
    public static final String NORMAL_QUEUE = "cyz_normal_queue";
    public static final String DELAY_KEY = "cyz_delay_key";
    public static final String NORMAL_KEY = "cyz_normal_key";

    //声明交换机
    @Bean(DELAY_EXCHANGE)
    public Exchange delayExchange() {
        return ExchangeBuilder.directExchange(DELAY_EXCHANGE).build();
    }

    @Bean(NORMAL_EXCHANGE)
    public Exchange normalExchange() {
        return ExchangeBuilder.directExchange(NORMAL_EXCHANGE).build();
    }

    @Bean(DELAY_QUEUE)
    public Queue delayQueue() {
        /**
         * 消息发送给延时队列
         * 设置延时队列的过期时间为5秒钟
         * 5秒之后,延时队列将消息发送给普通队列
         */
        Map<String, Object> args = new HashMap<>();
        args.put("x-dead-letter-exchange", NORMAL_EXCHANGE);
        args.put("x-dead-letter-routing-key", NORMAL_KEY);
        args.put("x-message-ttl", 5000);
        return QueueBuilder.durable(DELAY_QUEUE).withArguments(args).build();
    }

    @Bean(NORMAL_QUEUE)
    public Queue normalQueue() {
        return QueueBuilder.durable(NORMAL_QUEUE).build();
    }


    @Bean
    public Binding bingingToDelay(@Qualifier(DELAY_QUEUE) Queue queue,
                                  @Qualifier(DELAY_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(DELAY_KEY).noargs();
    }

    @Bean
    public Binding bingingToNormal(@Qualifier(NORMAL_QUEUE) Queue queue,
                                   @Qualifier(NORMAL_EXCHANGE) Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(NORMAL_KEY).noargs();
    }

}

消费者

MessageReceiverDelay.java
package com.cyz.config.delayqueue;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MessageReceiverDelay {

    @RabbitListener(queues = RabbitConfigDelay.NORMAL_QUEUE)
    public void receiveEmailMessage(String message) {
        System.out.println(System.currentTimeMillis());
        System.out.println("cyz_delay_queue_email Received Email message: " + message);
    }
}

生产者

MessageSenderDelay.java
package com.cyz.config.delayqueue;

import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessageSenderDelay {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    public void sendEmailMessage() {
        System.out.println(System.currentTimeMillis());
        rabbitTemplate.convertAndSend(RabbitConfigDelay.DELAY_EXCHANGE, RabbitConfigDelay.DELAY_KEY,"delay");
    }
}

测试

上面配置的时间是5秒,这边刚好差5秒

消息确认及设置重试次数

@RabbitListener(queues = RabbitConfig_SLA.SLA_TIMEOUT_TASK_QUEUE_NAME)
    private void consumerTimeoutTask(Message message, Channel channel) throws Exception {
        //先转换消息为对象
        SendMsgTemplate sendMsgTemplate = JSONObject.parseObject(new String(message.getBody()), SendMsgTemplate.class);
        log.info("enter consumerTimeoutTask {}", sendMsgTemplate);
        try {
            consumeTimeoutTask(sendMsgTemplate);
            //确认消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            log.info("finish consumerTimeoutTask {}", sendMsgTemplate);
        } catch (IOException e) {
            //消费失败重新入队
            log.error("consumerTimeoutTask error {}", sendMsgTemplate);
            handleException(message, channel);
        }
    }


/**
     * 处理异常,如果重试次数达到最大重试次数就直接确认消息
     */
    private void handleException(Message message, Channel channel) throws Exception {
        // 处理消息处理失败的逻辑
        int retryCount = getRetryCount(message);
        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        if (retryCount < 3) {
            // 重新入队列,增加重试次数
            message.getMessageProperties().getHeaders().put("retryCount", ++retryCount);
            rabbitTemplate.convertAndSend(RabbitConfig_SLA.EXCHANGE_SLA_NAME, RabbitConfig_SLA.SLA_TIMEOUT_TASK_KEY, message);
        } else {
            // 超过最大重试次数
            log.warn("Max retry count reached,discard the message {}", message.getMessageProperties().getDeliveryTag());
        }
    }

    /**
     * 获取重试了次数
     */
    private int getRetryCount(Message message) {
        // 从消息头中获取重试次数
        Integer retryCount = message.getMessageProperties().getHeader("retryCount");
        return retryCount != null ? retryCount : 0;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值