SpringBoot整合RabbitMq实现ACK机制--消息回退机制--消息确认机制

1. 环境配置

pom.xml

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <dependencies>
        <!-- rabbitMQ -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <!-- 测试类 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

application.yml

server:
  port: 9001
spring:
  rabbitmq:
    host: 127.0.0.1
    virtual-host: /
    username: guest
    password: guest
    listener:
      simple:
        prefetch: 1 # 每次只能获取一条消息 处理完成才能获取下一条 能者多劳模式 默认为预取机制
        acknowledge-mode: manual # 设置消费端手动ack确认
        retry:
          enabled: true # 是否支持重试
    publisher-confirm-type: correlated # 确认消息已发送到交换机(Exchange)
    publisher-returns: true #  确认消息已发送到队列(Queue) 消息在未被队列接收时返回

2. RabbitMq配置

RabbitAdmin配置

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitAdminConfig {

    @Value("${spring.rabbitmq.host}")
    private String host;
    @Value("${spring.rabbitmq.username}")
    private String username;
    @Value("${spring.rabbitmq.password}")
    private String password;
    @Value("${spring.rabbitmq.virtualhost}")
    private String virtualhost;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(host);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualhost);
        // 配置发送确认回调时,次配置必须配置,否则即使在RabbitTemplate配置了ConfirmCallback也不会生效
        connectionFactory.setPublisherConfirms(true);// 开启消息发布者确认
        connectionFactory.setPublisherReturns(true);// 确认消息发送到队列,如未被队列接收时返回
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

2.1 消息发送确认机制

为确保消息发送的准确性,设置发布时确认,确认消息是否到达 Broker 服务器 消息只要被Broker接收,就会触发 ConfirmCallbackConfig 回调

消息接收确认回调

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

import javax.annotation.PostConstruct;

/**
 * 消息只要被RabbitMq Broker接收 就会触发本回调
 * 消息发送确认回调
 */
@Component
public class ConfirmCallbackConfig implements RabbitTemplate.ConfirmCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct // @PostContruct是spring框架的注解,在⽅法上加该注解会在项⽬启动的时候执⾏该⽅法,也可以理解为在spring容器初始化的时候执行
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
    }

    /**
     * 交换机不管是否收到消息的一个回调方法
     *
     * @param correlationData 消息相关数据
     * @param ack             交换机是否收到消息
     * @param cause           失败原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) { // 消息投递到broker 的状态,true表示成功
            System.out.println("消息发送到Broker成功!");
        } else { // 发送异常
            System.out.println("发送异常原因 = " + cause);
        }
    }
}

2.2 消息投递确认机制

如果消息未能投递到目标 queue 里将触发回调 returnCallback ,一旦向 queue 投递消息未成功,这里一般会记录下当前消息的详细投递数据,方便后续做重发或者补偿等操作

消息投递机制回调接口

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

import javax.annotation.PostConstruct;

/**
* 如果消息未能投递到目标queue里将触发本回调 returnCallback ,
 * 一旦向 queue 投递消息未成功,这里一般会记录下当前消息的详细投递数据,方便后续做重发或者补偿等操作
* */
@Component
public class ReturnCallbackConfig implements RabbitTemplate.ReturnCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct // @PostContruct是spring框架的注解,在⽅法上加该注解会在项⽬启动的时候执⾏该⽅法,也可以理解为在spring容器初始化的时候执
    public void init() {
        rabbitTemplate.setReturnCallback(this);
    }

    @Override
    public void returnedMessage(Message message, int i, String s, String s1, String s2) {
        System.out.println("returnCallback ..............");
        System.out.println(message);// 消息本身
        System.out.println(i);// index
        System.out.println(s);
        System.out.println(s1);
        System.out.println(s2);// 队列名称
    }
}

2.3 ACK消息签收机制

为确保消息 消费成功,需设置消费者消息确认机制,如果消费失败或异常了,可做补偿机制

以下是三种 channel 签收方式

  1. basicAck 消息确认
  2. basicNack 消息回退
  3. basicReject 消息拒绝

消费者消息确认机制

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


import java.io.IOException;

@Component // 如果把这个注释掉,就不会自动创建 simple.queue队列,则生产消息会触发 returnCallback 回调
public class ACKConfirmListener {
    @RabbitListener(queuesToDeclare = @Queue(value = "simple.queue", durable = "true")) // queuesToDeclare 自动声明队列
    public void ackListener(String msg, Channel channel, Message message) throws IOException {
        try {
            // 消息
            System.out.println("msg = " + msg);
            throw new RuntimeException("消费者故意抛出异常......");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("消息消费异常,重回队列......");
            /**
             * 出现异常,把消息重新投递回队列中,如一直有异常会一直循环投递
             * deliveryTag:表示消息投递序号。
             * multiple:是否批量确认。
             * requeue:值为 true 消息将重新入队列。
             */
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
        /**
         * 消息确认 ACK
         * deliveryTag:表示消息投递序号,每次消费消息或者消息重新投递后,deliveryTag都会增加
         * multiple:是否批量确认,值为 true 则会一次性 ack所有小于当前消息 deliveryTag 的消息。
         */
        System.out.println("ACK消息消费确认.....")
        
        // 消息确认 basicAck
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
       
        // 消息拒绝 basicReject
        //channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
    }
}

3. 消息生产者

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class MqTest {

    // 注入 rabbitmq
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    // 直接模式(Direct)
    public void testSend() {
        rabbitTemplate.convertAndSend("simple.queue", "ACK消息确认机制生产者......");
    }

https://blog.csdn.net/qq_48721706/article/details/125194646

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
实现 Spring BootRabbitMQ 和 WebSocket 结合的方式主要有以下几个步骤: 1. 创建 Spring Boot 项目,添加 RabbitMQ 和 WebSocket 的相关依赖。 2. 创建 RabbitMQ 队列和交换机,用于发送消息。 3. 创建 WebSocket 配置类,配置 WebSocket 的相关参数。 4. 创建 WebSocket 处理器类,处理 WebSocket 的连接、消息发送等操作。 5. 创建 RabbitMQ 消息监听器类,监听 RabbitMQ 队列消息,将消息发送给 WebSocket 处理器。 下面是具体的实现步骤: 1. 创建 Spring Boot 项目,添加 RabbitMQ 和 WebSocket 的相关依赖。 在 pom.xml 添加以下依赖: ```xml <dependencies> <!-- RabbitMQ 相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-- WebSocket 相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies> ``` 2. 创建 RabbitMQ 队列和交换机,用于发送消息。 在 RabbitMQ 创建一个交换机和一个队列,然后将队列绑定到交换机上。这里我们使用 RabbitMQ 的默认交换机和队列。 ```java @Configuration public class RabbitMQConfig { @Bean public Queue queue() { return new Queue("websocket"); } @Bean public DirectExchange exchange() { return new DirectExchange(""); } @Bean public Binding binding(Queue queue, DirectExchange exchange) { return BindingBuilder.bind(queue).to(exchange).with("websocket"); } } ``` 3. 创建 WebSocket 配置类,配置 WebSocket 的相关参数。 ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS(); } } ``` 4. 创建 WebSocket 处理器类,处理 WebSocket 的连接、消息发送等操作。 ```java @Component public class WebSocketHandler implements WebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class); private SimpMessagingTemplate messagingTemplate; @Autowired public WebSocketHandler(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { logger.info("WebSocket connected: {}", session.getId()); } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { logger.info("WebSocket received message: {}", message.getPayload()); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { logger.error("WebSocket transport error: {}", exception.getMessage()); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { logger.info("WebSocket disconnected: {}", session.getId()); } @Override public boolean supportsPartialMessages() { return false; } public void sendMessage(String message) { messagingTemplate.convertAndSend("/topic/messages", message); } } ``` 5. 创建 RabbitMQ 消息监听器类,监听 RabbitMQ 队列消息,将消息发送给 WebSocket 处理器。 ```java @Component public class RabbitMQListener { private static final Logger logger = LoggerFactory.getLogger(RabbitMQListener.class); private WebSocketHandler webSocketHandler; @Autowired public RabbitMQListener(WebSocketHandler webSocketHandler) { this.webSocketHandler = webSocketHandler; } @RabbitListener(queues = "websocket") public void handleMessage(String message) { logger.info("RabbitMQ received message: {}", message); webSocketHandler.sendMessage(message); } } ``` 至此,Spring BootRabbitMQ 和 WebSocket 结合的实现就完成了。我们可以通过 RabbitMQ 发送消息到队列,然后监听器会将消息发送给 WebSocket 处理器,处理器再将消息发送给 WebSocket 客户端。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我三胖哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值