springboot整合rabbitmq发布确认

出现情况:在生产环境中rabbitmq服务器由于一些不明原因,导致rabbitmq重启,在重启期间生产者消息投递失败,导致消息丢失,需要手动处理和恢复。在rabbitmq集群不可用,无法投递消息的时候。

发布确认

在这里插入图片描述

1.yml配置

发布确认的yml配置

    publisher-confirms: true

yml配置代码

spring:
  rabbitmq:
    host: 192.168.64.137
    port: 5672
    username: fxr
    password: 123
    virtual-host: /
#    publisher-confirm-type: correlated
#    开启发布确认类型
#    ⚫ NONE
#    禁用发布确认模式,是默认值
#    ⚫ CORRELATED
#    发布消息成功到交换器后会触发回调方法
#    ⚫ SIMPLE (发一条确认一条,不用)
#    经测试有两种效果,其一效果和 CORRELATED 值一样会触发回调方法,
#    其二在发布消息成功后使用 rabbitTemplate 调用 waitForConfirms 或 waitForConfirmsOrDie 方法
#    等待 broker 节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是
#    waitForConfirmsOrDie 方法如果返回 false 则会关闭 channel,则接下来无法发送消息到 broker
    publisher-confirms: true
#    路由不出去的消息会回退
#    publisher-returns: true

2.配置类代码

package com.cherry.rabbitmqttl.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 ConfirmConfig {
    
    
    // 交换机
    public static final String CONFIRM_EXCHANGE_NAME = "confirm_exchange";
    // 队列
    public static final String CONFIRM_QUEUE_NAME = "confirm_queue";
    // routingKey
    public static final String CONFIRM_ROUTING_KEY = "key1";


    // 声明交换机
    @Bean("confirmExchange")
    public DirectExchange confirmExchange(){
    
    
        return new DirectExchange(CONFIRM_EXCHANGE_NAME);
    }

    // 队列
    @Bean("confirmQueue")
    public Queue confirmQueue(){
    
    
        return QueueBuilder.durable(CONFIRM_QUEUE_NAME).build();
    }

    @Bean
    public Binding queueBindingExchange(@Qualifier("confirmQueue")Queue confirmQueue,
                                        @Qualifier("confirmExchange")DirectExchange confirmExchange){
    
    
        return BindingBuilder.bind(confirmQueue).to(confirmExchange).with(CONFIRM_ROUTING_KEY);
    }


}

3.生产者代码

package com.cherry.rabbitmqttl.controller;

import com.cherry.rabbitmqttl.config.ConfirmConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 测试确认开始发消息
 */
@Slf4j
@RequestMapping("/confirm")
@RestController
public class ConfirmProductController {
    
    

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 交换机错误时交换机会显示交换机未收到消息的错误信息,
     * routingkey错误时会显示交换机收到消息
     * 发送消息内容,你好啊key1
     * Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'confirm_exchange1' in vhost '/', class-id=60, method-id=40)
     * 交换机还未收到 id 为:ID=1消息,由于原因:channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'confirm_exchange1' in vhost '/', class-id=60, method-id=40)
     * 送消息内容,你好啊key12
     * 交换机已经收到 id 为:ID=2的消息
     * @param message
     */
    // 发消息
    // ID唯一标识
    // routingkey错误时没法获得失败回调
    @GetMapping("/sendMsg/{message}")
    public void sendMessage(@PathVariable String message){
    
    
        // 正常发送消息: 交换机和队列都收到了
        CorrelationData correlationData3 =  new CorrelationData("ID=0");
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME,
                ConfirmConfig.CONFIRM_ROUTING_KEY,
                message,
                correlationData3);
        log.info("发送消息内容,{}", message + "key0" );
        log.info("______________________________________________________________________");

        // 交换机错误发送消息:交换机未收到,队列未收到
        CorrelationData correlationData1 =  new CorrelationData("ID=1");
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME+1,
                ConfirmConfig.CONFIRM_ROUTING_KEY + "key1",
                message + "key1",
                correlationData1);
        log.info("发送消息内容,{}", message + "key1");
        log.info("______________________________________________________________________");

        // routingkey错误发送消息:交换机收到,队列未收到
        CorrelationData correlationData2 =  new CorrelationData("ID=2");
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME,
                ConfirmConfig.CONFIRM_ROUTING_KEY + "2",
                message + "key12",
                correlationData2);
        log.info("发送消息内容,{}", message + "key12");


    }
}

4.消费者代码

package com.cherry.rabbitmqttl.consumer;

import com.cherry.rabbitmqttl.config.ConfirmConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ConfirmConsumer {
    
    
    @RabbitListener(queues = ConfirmConfig.CONFIRM_QUEUE_NAME)
    public void receiveConfirm(Message message){
    
    
        String mesg = new String(message.getBody());
        log.info("接收到的队列confirm.queue消息:{}", mesg);
    }
}

5.发布确认的回调类

package com.cherry.rabbitmqttl.confirmcallback;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 感知不能正常消费的消息回调
 */
@Component
@Slf4j
public class MyCallBack implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {
    
    
    // 注入
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //  @PostConstruct注入功能再Autowired注入后注入
    @PostConstruct
    public void init(){
    
    
        rabbitTemplate.setConfirmCallback(this);
    }

    /**
     * 交换机不管是否收到消息的一个回调方法
     * CorrelationData
     * 消息相关数据
     * ack
     * 交换机是否收到消息
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, java.lang.String cause) {
    
    
        String id=correlationData!=null?correlationData.getId():"";
        if(ack){
    
    
            log.info("交换机已经收到 id 为:{}的消息",id);
        }else{
    
    
            log.info("交换机还未收到 id 为:{}消息,由于原因:{}",id,cause);
        }
    }

}

6.pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>
    <groupId>com.cherry</groupId>
    <artifactId>rabbitmqttl</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rabbitmqttl</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--RabbitMQ 测试依赖-->
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

猜你喜欢

转载自blog.csdn.net/m0_49382941/article/details/129789162