springboot 整合 RabbitMQ

springboot 整合 RabbitMQ

背景

多线程读取大文件后需要分时段进行第三方接口的调用【由于外部接口限制API30s才可以调用一次】,所以我们将使用RabbitMQ的延时消费的方式进行外部接口的调用,以保证项目程序的正常运行

RabbitMQ介绍

RabbitMQ介绍
RabbitMQ 快速下载安装

详情看上 ,本篇文章只解决背景问题,整合springboot+RabbitMQ

springboot 整合 RabbitMQ[延时队列]

延时队列

延时队列是存储延时消息的队列,延时消息就是生产者发送了一条消息,但是不希望该消息不要被立即消费,而是设置一个延时时间,等过了这个时间再消费消息

延时队列安装插件

RabbitMQ3.6版本以前一般采用死信队列 + TTL过期时间的方式来实现延迟队列。
从3.6以后的版本,RabbitMQ官方提供了延迟对列的插件官方下载地址 rabbitmq_delayed_message_exchange-3.8.0.ez 这个插件放到 RabbitMQ 安装目录的 plugins 文件中

RabbitMQ 安装 sbin 文件中用 cmd 执行命令:

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

然后登陆web页面,可以查看到交换机tab下新增了x-delayed-message

插件原理

image-20220309103350255

  • 原始的 死信队列+ TTL 的模式,消息首先会路由到一个正常的队列,根据设置的 TTL 进入死信队列,与之不同的是通过 x-delayed-message 声明的交换机,它的消息在发布之后不会立即进入队列,先将消息保存至 Mnesia(一个分布式数据库管理系统,适合于电信和其它需要持续运行和具备软实时特性的 Erlang 应用)
  • 这个插件将会尝试确认消息是否过期,首先要确保消息的延迟范围是 Delay > 0, Delay =< ?ERL_MAX_T(在 Erlang 中可以被设置的范围为 (2^32)-1 毫秒),如果消息过期通过 x-delayed-type 类型标记的交换机投递至目标队列,整个消息的投递过程也就完成了

代码具体实现

pom.xml

<!--springboot  2.3.1.RELEASE-->
<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>

application.properties


# 由于MQ只在本项目中,未跨项目 所有配置文件一份,跨项目则需要分开配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#开启消息的return机制
spring.rabbitmq.publisher-confirms=true
#确认消息已发送到队列
spring.rabbitmq.publisher-returns=true
#开启消息的confirm机制 correlated:开启;NONE:关闭
spring.rabbitmq.publisher-confirms-type=correlated
#在需要使用消息的return机制时候,此参数必须设置为true
spring.rabbitmq.template.mandatory=true

spring.rabbitmq.listener.type=simple
#消费方消息确认:手动确认
spring.rabbitmq.listener.simple.acknowledge-mode=manual
#决定被拒绝的消息是否重新入队;默认是true(与参数acknowledge-mode有关系)
spring.rabbitmq.listener.simple.default-requeue-rejected=false

静态常量抽取

/**
 *  MQ相关常量
 **/
public class MqConstant {

    // 延时交换机
    public static final String MQ_WEBSITE_FILM_DELAY_EXCHANGE = "website_film_delay_exchange";

    // 延时队列名称
    public static final String MQ_WEBSITE_FILM_QUEUE = "website_film_delay_queue";

    // 普通交换机
    public static final String MQ_WEBSITE_NORMAL_EXCHANGE = "website_normal_exchange";

    // 普通队列名称
    public static final String MQ_WEBSITE_NORMAL_QUEUE = "website_normal_queue";

    // 普通交换机路由键
    public static final String MQ_WEBSITE_NORMAL_ROUTING_KEY = "website_normal_routing_key";

}

配置类

RabbitConfig

主要是队列,交换机的配置绑定

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * RabbitMQ的配置 主要是队列,交换机的配置绑定
 **/
@Configuration
public class RabbitConfig {

    //https://blog.csdn.net/weixin_38192427/article/details/120509586
    /**
     * durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
     * exclusive 表示该消息队列是否只在当前connection生效,默认是false
     * auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
     */
    // 延时队列
    @Bean
    public Queue delayQueue() {
        return new Queue(MqConstant.MQ_WEBSITE_FILM_QUEUE, true,false,false);
    }

    /**
     * 交换机说明:
     * durable="true" rabbitmq重启的时候不需要创建新的交换机
     * auto-delete 表示交换机没有在使用时将被自动删除 默认是false
     * direct交换器相对来说比较简单,匹配规则为:如果路由键匹配,消息就被投送到相关的队列
     * topic交换器你采用模糊匹配路由键的原则进行转发消息到队列中
     * fanout交换器中没有路由键的概念,他会把消息发送到所有绑定在此交换器上面的队列中。
     */
    // 延时交换机 设置
    public FanoutExchange delayExchange() {
        //使用自定义交换器
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        FanoutExchange fanoutExchange = new FanoutExchange(MqConstant.MQ_WEBSITE_FILM_DELAY_EXCHANGE, true, false, args);
        fanoutExchange.setDelayed(true);
        return fanoutExchange;
    }

    // 绑定延时队列与延时交换机
    @Bean
    public Binding delayBind() {
        return BindingBuilder.bind(delayQueue()).to(delayExchange());
    }

    // ------------------------普通队列------------------------
    // 普通队列
    @Bean
    public Queue normalQueue() {
        return new Queue(MqConstant.MQ_WEBSITE_NORMAL_QUEUE, true);
    }

    // 普通交换机
    @Bean
    public DirectExchange normalExchange() {
        return new DirectExchange(MqConstant.MQ_WEBSITE_NORMAL_EXCHANGE, true, false);
    }

    // 绑定普通消息队列
    @Bean
    public Binding normalBind() {
        return BindingBuilder.bind(normalQueue()).to(normalExchange()).with(MqConstant.MQ_WEBSITE_NORMAL_ROUTING_KEY);
    }

    // 定义消息转换器
    @Bean
    public Jackson2JsonMessageConverter jsonMessageConverter() {
        return new Jackson2JsonMessageConverter();
    }


    /** ======================== 定制一些处理策略 =============================*/

    /**
     * 定制化amqp模版
     * <p>
     * Rabbit MQ的消息确认有两种。
     * <p>
     * 一种是消息发送确认:这种是用来确认生产者将消息发送给交换机,交换机传递给队列过程中,消息是否成功投递。
     * 发送确认分两步:一是确认是否到达交换机,二是确认是否到达队列
     * <p>
     * 第二种是消费接收确认:这种是确认消费者是否成功消费了队列中的消息。
     */
    // 定义消息模板用于发布消息,并且设置其消息转换器
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        // 消息发送失败返回到队列中, yml需要配置 publisher-returns: true
        rabbitTemplate.setMandatory(true);

        /**
         * 使用该功能需要开启消息确认,yml需要配置 publisher-confirms: true
         * 通过实现ConfirmCallBack接口,用于实现消息发送到交换机Exchange后接收ack回调
         * correlationData  消息唯一标志
         * ack              确认结果
         * cause            失败原因
         */
        rabbitTemplate.setConfirmCallback(new MsgSendConfirmCallback());
        /**
         * 使用该功能需要开启消息返回确认,yml需要配置 publisher-returns: true
         * 通过实现ReturnCallback接口,如果消息从交换机发送到对应队列失败时触发
         * message    消息主体 message
         * replyCode  消息主体 message
         * replyText  描述
         * exchange   消息使用的交换机
         * routingKey 消息使用的路由键
         */
        rabbitTemplate.setReturnCallback(new MsgSendReturnCallback());
        rabbitTemplate.setMessageConverter(jsonMessageConverter());
        return rabbitTemplate;
    }

    // --------------------------使用RabbitAdmin启动服务便创建交换机和队列--------------------------
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        // 只有设置为 true,spring 才会加载 RabbitAdmin 这个类
        rabbitAdmin.setAutoStartup(true);
        // 创建延时交换机和对列
        rabbitAdmin.declareExchange(delayExchange());
        rabbitAdmin.declareQueue(delayQueue());
        // 创建普通交换机和对列
        rabbitAdmin.declareExchange(normalExchange());
        rabbitAdmin.declareQueue(normalQueue());
        return new RabbitAdmin(connectionFactory);
    }

}

RabbitConfirmConfig

RabbitMQ的配置 消息发送到 exchange,queue 的回调函数

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * RabbitMQ的配置 消息发送到 exchange,queue 的回调函数
 **/
@Configuration
public class RabbitConfirmConfig {

    private static Logger logger = LogManager.getLogger(RabbitConfirmConfig.class);

    /** ======================== 定制一些处理策略 =============================*/
    /**
     * 定制化amqp模版
     * <p>
     * Rabbit MQ的消息确认有两种。
     * <p>
     * 一种是消息发送确认:这种是用来确认生产者将消息发送给交换机,交换机传递给队列过程中,消息是否成功投递。
     * 发送确认分两步:一是确认是否到达交换机,二是确认是否到达队列
     * <p>
     * 第二种是消费接收确认:这种是确认消费者是否成功消费了队列中的消息。
     * Springboot中使用ConfirmCallback和ReturnCallback
     * 注意:
     *  在需要使用消息的return机制时候,mandatory参数必须设置为true
     * 新版本开启消息的confirm配置publisher-confirms已经过时,改为使用publisher-confirm-type参数设置(correlated:开启;NONE:关闭)
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        rabbitTemplate.setConnectionFactory(connectionFactory);
//        设置开启Mandatory才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数
        rabbitTemplate.setMandatory(true);
        /**
         * 使用该功能需要开启消息确认 无论成功与否,需要配置 publisher-confirms: true
         * 通过实现ConfirmCallBack接口,用于实现消息发送到交换机Exchange后接收ack回调
         * correlationData  消息唯一标志
         * ack              确认结果
         * cause            失败原因
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            logger.info("ConfirmCallback:" + "相关数据:" + correlationData);
            logger.info("ConfirmCallback:" + "确认情况:" + ack);
            logger.info("ConfirmCallback:" + "原因:" + cause);
        });
        /**
         * 消息从Exchange路由到Queue失败的回调
         * 使用该功能需要开启消息返回确认,需要配置 publisher-returns: true
         * 通过实现ReturnCallback接口,如果消息从交换机发送到对应队列失败时触发
         * message    消息主体 message
         * replyCode  消息主体 message
         * replyText  描述
         * exchange   消息使用的交换机
         * routingKey 消息使用的路由键
         */
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            logger.info("ReturnCallback:" + "消息:" + message);
            logger.info("ReturnCallback:" + "回应码:" + replyCode);
            logger.info("ReturnCallback:" + "回应信息:" + replyText);
            logger.info("ReturnCallback:" + "交换机:" + exchange);
            logger.info("ReturnCallback:" + "路由键:" + routingKey);
        });
        return rabbitTemplate;
    }
}

MsgSendReturnCallback

消息从交换机发送到对应队列失败时触发

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

@Component
public class MsgSendReturnCallback implements RabbitTemplate.ReturnCallback {
    private static Logger logger = LogManager.getLogger(MsgSendReturnCallback.class);

    /**
     * 使用该功能需要开启消息返回确认,yml需要配置 publisher-returns: true
     * message    消息主体 message
     * replyCode  消息主体 message
     * replyText  描述
     * exchange   消息使用的交换机
     * routingKey 消息使用的路由键
     * <p>
     * PS:通过实现ReturnCallback接口,如果消息从交换机发送到对应队列失败时触发
     * </p>
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        if (exchange.equals(MqConstant.MQ_WEBSITE_FILM_DELAY_EXCHANGE)) {
            // 如果配置了发送回调ReturnCallback,rabbitmq_delayed_message_exchange插件会回调该方法,因为发送方确实没有投递到队列上,只是在交换器上暂存,等过期/时间到了才会发往队列。
            // 所以如果是延迟队列的交换器,则直接放过,并不是bug
            return;
        }
        String correlationId = message.getMessageProperties().getCorrelationId();
        logger.debug("消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {}  路由键: {}", correlationId, replyCode, replyText, exchange, routingKey);
    }
}

AckListener

Consumer ACK机制

import com.rabbitmq.client.Channel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * Consumer ACK机制:
 *  1. 设置手动签收。acknowledge="manual"
 *  2. 让监听器类实现ChannelAwareMessageListener接口
 *  3. 如果消息成功处理,则调用channel的 basicAck()签收
 *  4. 如果消息处理失败,则调用channel的basicNack()拒绝签收,broker重新发送给consumer
 *	
 */

@Component
public class AckListener implements ChannelAwareMessageListener {

    private static Logger logger = LogManager.getLogger(AckListener.class);

    Map<Long,Integer> map;
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            //1.接收转换消息
            logger.info("MQ接收转换消息[{}]",new String(message.getBody()));

            //2. 处理业务逻辑
            logger.info("处理业务逻辑...");
            int i = 3/0;//出现错误
            //3. 手动签收
            channel.basicAck(deliveryTag,false);
        } catch (Exception e) {
            //e.printStackTrace();
            logger.error("MQ拒绝签收逻辑...");
            /*
                4.拒绝签收
                第三个参数:requeue:重回队列。如果设置为true,则消息重新回到queue,broker会重新发送该消息给消费端
            */
            /*if(!map.containsKey(deliveryTag)){
                map.put(deliveryTag,1);
                channel.basicNack(deliveryTag,true,true);
            }else{
                //判断是否大于3次
                if(>3){
                     channel.basicNack(deliveryTag,false,true);
                    //记录
                }else{
                    channel.basicNack(deliveryTag,true,true);
                }

            }*/
            channel.basicNack(deliveryTag,false,false);
            //channel.basicReject(deliveryTag,true);
        }
    }
}

MsgProductionService

发送消息到MQ 业务类 消费生产

import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 发送消息到MQ
 **/
@Service("msgProductionService")
public class MsgProductionService {

    @Resource
    private RabbitTemplate rabbitTemplate;

    // 发送延时信息
    public void sendTimeoutMsg(String exchange,String content, String routingKey, int delay) {
        // 通过广播模式发布延时消息,会广播至每个绑定此交换机的队列,这里的路由键没有实质性作用
        rabbitTemplate.convertAndSend(exchange, routingKey, content, message -> {
            message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
            // 毫秒为单位,指定此消息的延时时长
            message.getMessageProperties().setDelay(delay * 1000);
            return message;
        });
    }
    // 发送普通消息
    public void sendMsg(String exchange,String routingKey, String content) {
        // DirectExchange类型的交换机,必须指定对应的路由键
        rabbitTemplate.convertAndSend(exchange, routingKey, content);
    }
}

MsgComsumerService

MQ消费 消费者【小编这里是在同一个项目中实现的,生产和消费】

import com.rabbitmq.client.Channel;
import com.zy.website.service.FilmService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;

/**
 *  MQ 消费者
 **/
@Service("msgComsumerService")
public class MsgComsumerService {

    private static Logger logger = LogManager.getLogger(MsgComsumerService.class);

    @Resource
    FilmService filmService;//自己业务具体实现类注入

    // 监听消费延时消息
    @RabbitListener(queues = {"website_film_delay_queue"})
    @RabbitHandler
    public void process(String content, Message message, Channel channel) throws IOException {
        try {
            // 消息的可定确认,第二个参数如果为true将一次性确认所有小于deliveryTag的消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            //调用方法消费消息 自己业务具体实现类
            filmService.getFilmInfoByExternalApi(content);
            logger.info("延迟队列消息[{}]被消费!!",content);
        } catch (Exception e) {
            logger.error("延迟队列消息 处理失败:{}", e.getMessage());
            // 直接拒绝消费该消息,后面的参数一定要是false,否则会重新进入业务队列,不会进入死信队列
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            /*// ack返回false,requeue-true并重新回到队列
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);*/
        }
    }

    // 消费普通消息
    @RabbitListener(queues = {"website_normal_queue"})
    @RabbitHandler
    public void process1(String content, Message message, Channel channel) throws IOException {
        try {
            logger.info("普通队列的内容[{}]", content);
            // 消息的可定确认,第二个参数如果为true将一次性确认所有小于deliveryTag的消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            logger.info("普通信息处理完毕");
        } catch (Exception e) {
            logger.error("处理失败:{}", e.getMessage());
            // 直接拒绝消费该消息,后面的参数一定要是false,否则会重新进入业务队列,不会进入死信队列
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
        }
    }
}

代码实现完成,这只是简单实现,复杂还需要研究。。。。。


RabbitMQ的具体详细配置项

基础配置项

spring.rabbitmq.host: 默认localhost
spring.rabbitmq.port: 默认5672
spring.rabbitmq.username: 用户名
spring.rabbitmq.password: 密码
spring.rabbitmq.virtual-host: 连接到代理时用的虚拟主机
spring.rabbitmq.addresses: 连接到server的地址列表(以逗号分隔),先addresses后host 
spring.rabbitmq.requested-heartbeat: 请求心跳超时时间,0为不指定,如果不指定时间单位默认为妙
spring.rabbitmq.publisher-confirms: 是否启用【发布确认】,默认false
spring.rabbitmq.publisher-returns: 是否启用【发布返回】,默认false
spring.rabbitmq.connection-timeout: 连接超时时间,单位毫秒,0表示永不超时 

SSL

spring.rabbitmq.ssl.enabled: 是否支持ssl,默认false
spring.rabbitmq.ssl.key-store: 持有SSL certificate的key store的路径
spring.rabbitmq.ssl.key-store-password: 访问key store的密码
spring.rabbitmq.ssl.trust-store: 持有SSL certificates的Trust store
spring.rabbitmq.ssl.trust-store-password: 访问trust store的密码
spring.rabbitmq.ssl.trust-store-type=JKS:Trust store 类型.
spring.rabbitmq.ssl.algorithm: ssl使用的算法,默认由rabiitClient配置
spring.rabbitmq.ssl.validate-server-certificate=true:是否启用服务端证书验证
spring.rabbitmq.ssl.verify-hostname=true 是否启用主机验证

缓存cache

spring.rabbitmq.cache.channel.size: 缓存中保持的channel数量
spring.rabbitmq.cache.channel.checkout-timeout: 当缓存数量被设置时,从缓存中获取一个channel的超时时间,单位毫秒;如果为0,则总是创建一个新channel
spring.rabbitmq.cache.connection.size: 缓存的channel数,只有是CONNECTION模式时生效
spring.rabbitmq.cache.connection.mode=channel: 连接工厂缓存模式:channel 和 connection

Listener

spring.rabbitmq.listener.type=simple: 容器类型.simple或direct
 
spring.rabbitmq.listener.simple.auto-startup=true: 是否启动时自动启动容器
spring.rabbitmq.listener.simple.acknowledge-mode: 表示消息确认方式,其有三种配置方式,分别是none、manual和auto;默认auto
spring.rabbitmq.listener.simple.concurrency: 最小的消费者数量
spring.rabbitmq.listener.simple.max-concurrency: 最大的消费者数量
spring.rabbitmq.listener.simple.prefetch: 一个消费者最多可处理的nack消息数量,如果有事务的话,必须大于等于transaction数量.
spring.rabbitmq.listener.simple.transaction-size: 当ack模式为auto时,一个事务(ack间)处理的消息数量,最好是小于等于prefetch的数量.若大于prefetch, 则prefetch将增加到这个值
spring.rabbitmq.listener.simple.default-requeue-rejected: 决定被拒绝的消息是否重新入队;默认是true(与参数acknowledge-mode有关系)
spring.rabbitmq.listener.simple.missing-queues-fatal=true 若容器声明的队列在代理上不可用,是否失败; 或者运行时一个多多个队列被删除,是否停止容器
spring.rabbitmq.listener.simple.idle-event-interval: 发布空闲容器的时间间隔,单位毫秒
spring.rabbitmq.listener.simple.retry.enabled=false: 监听重试是否可用
spring.rabbitmq.listener.simple.retry.max-attempts=3: 最大重试次数
spring.rabbitmq.listener.simple.retry.max-interval=10000ms: 最大重试时间间隔
spring.rabbitmq.listener.simple.retry.initial-interval=1000ms:第一次和第二次尝试传递消息的时间间隔
spring.rabbitmq.listener.simple.retry.multiplier=1: 应用于上一重试间隔的乘数
spring.rabbitmq.listener.simple.retry.stateless=true: 重试时有状态or无状态
 
spring.rabbitmq.listener.direct.acknowledge-mode= ack模式
spring.rabbitmq.listener.direct.auto-startup=true 是否在启动时自动启动容器
spring.rabbitmq.listener.direct.consumers-per-queue= 每个队列消费者数量.
spring.rabbitmq.listener.direct.default-requeue-rejected= 默认是否将拒绝传送的消息重新入队.
spring.rabbitmq.listener.direct.idle-event-interval= 空闲容器事件发布时间间隔.
spring.rabbitmq.listener.direct.missing-queues-fatal=false若容器声明的队列在代理上不可用,是否失败.
spring.rabbitmq.listener.direct.prefetch= 每个消费者可最大处理的nack消息数量.
spring.rabbitmq.listener.direct.retry.enabled=false  是否启用发布重试机制.
spring.rabbitmq.listener.direct.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message.
spring.rabbitmq.listener.direct.retry.max-attempts=3 # Maximum number of attempts to deliver a message.
spring.rabbitmq.listener.direct.retry.max-interval=10000ms # Maximum duration between attempts.
spring.rabbitmq.listener.direct.retry.multiplier=1 # Multiplier to apply to the previous retry interval.
spring.rabbitmq.listener.direct.retry.stateless=true # Whether retries are stateless or stateful.

Template

spring.rabbitmq.template.mandatory: 启用强制信息;默认false
spring.rabbitmq.template.receive-timeout: receive() 操作的超时时间
spring.rabbitmq.template.reply-timeout: sendAndReceive() 操作的超时时间
spring.rabbitmq.template.retry.enabled=false: 发送重试是否可用 
spring.rabbitmq.template.retry.max-attempts=3: 最大重试次数
spring.rabbitmq.template.retry.initial-interva=1000msl: 第一次和第二次尝试发布或传递消息之间的间隔
spring.rabbitmq.template.retry.multiplier=1: 应用于上一重试间隔的乘数
spring.rabbitmq.template.retry.max-interval=10000: 最大重试时间间隔

RabbitMQ学习系列

RabbitMQ 安装快速下载

springboot简单整合RabbitMQ

RabbitMQ消息队列

RabbitMQ 消息投递以及ACK机制

RabbitMQ 消息幂等性&顺序性&消息积压&面试问题

posted @ 2022-03-09 14:25  Mr*宇晨  阅读(422)  评论(0编辑  收藏  举报