RattitMQ

149 阅读19分钟

是什么

RabbitMQ 是众多消息中间件中的一种,作为服务与服务之间的缓冲层,增强服务的处理效率,减轻服务的压力,相对于其他MQ其拥有处理能力居中的每秒 10 万/QPS 的能力,产品持续迭代升级,应用较广。RabbitMQ 主要用于流量消峰,应用解耦,异步处理。

有什么

RabbitMQ 由主要有两部分组成。交换机队列。而Java访问RabbitMQ的整套则由消息生产者,信道,交换机,队列,消息消费者组成。由消息生产者通过信道发送消息到RabbitMQ交换机中,再由交换机分发到队列中,由消费者通过信道连接RabbitMQ,消费消息

在生产者将消息发送到RabbitMQ后生产者可以直接视为消息已被处理,并将被处理的情况告知用户,再由RabbitMQ自行将消息按照某些规则发送给一个或者多个消费者进行消费,RabbitMQ可以将这些消息进行“缓慢分发”,最终全部消费,完成对流量的消峰,由于消费者与生产者不进行直接交互,这又造成了两者之间的应用解耦,当消息被确认已经送达之后,生产者负责回复用户,Rabbit负责分发消息两者不需要在同一时间段内同时同时运行互相等待结果(生产者不需要等待MQ将消息分发到消费者手中在等消费者消费完毕,再讲消息消费成功告诉生产者,生产者在去做其他的事情)

消息生产者的知识点

消息生产者负责生产消息,通常在某些拥有大量数据需要处理且自身需要快速响应的应用通常都可以将消息交由RabbitMQ进行异步处理。以下列出了消息生产者中的知识点。

消息发布与确认

生产者将信道设置成 confin 模式,一旦信道进入confir 模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后, broker 就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经止确到达目的队列了,如果消息和队列是可持久化的,那么确认消息会在将消息写入磁盘之后发出, broker回传给生产者的确认消息中 delivery-tag 域包含了确认消息的序列号,此外 broker也可以设置basic.ack的 nultiple域,表小到这个序列号之前的所有消息都已经得到了处理。

infirm模式最大的好处在于他是异步的,一旦发布一条消息者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回方法来处理该确认消息,如果 Rabbit№Q因为自身内部错误导致消息丢失,就会发送一条nack消息,生产者应用程序同样可以在回调方法中处理该nack消息。

  1. 单个确认 单个发布确认只会在收到消息被确认后才会发送下一条消息,在一段时间内若该消息未被确认则抛出异常,会阻塞后面要发送的消息。

  2. 批量确认 批量确认是指在发送到一定数量的消息后在对此批数据一同确认,缺点是在其中一条发生确认失败时无法缺确定是哪一条,需要将批量中的数据进行单个尝试,确认是同步的,仍会阻塞后续消息的发送

  3. 异步确认 异步确认在消息发送失败后可以获得具体失败的消息,且不会发送阻塞,效率最高,在消息发送后将调用消息发布者的两个消息发布确认函数:成功函数与失败函数,当消息发送完毕后将回调这两个函数中的某一个,完成消息的确认操作。

开启发布确认

spring:
  rabbitmq:
    host: 192.168.124.132
    port: 5673
    username: root
    password: root
    virtual-host: /
    # 是否开启发布回调
    publisher-returns: true
    # 指定发布确认的类型
    #1.NONE值是禁用发布确认模式,是默认值
    #2.CORRELATED值是发布消息成功到交换器后会触发回调方法,
    #3.SIMPLE值经测试有两种效果,其一效果和CORRELATED值一样会触发回调方法,
    # 其二在发布消息成功后使用rabbitTemplate调用waitForConfirms或waitForConfirmsOrDie
    # 方法等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是waitForConfirmsOrDie
    # 方法如果返回false则会关闭channel,则接下来无法发送消息到broker;
    publisher-confirm-type: correlated

发布消息

@Component("mq_provider")
public class MQ_Provider {

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired //注入消息确认实现类对象
    private RabbitTemplate.ConfirmCallback confirmCallback;
    @Autowired //注入消息回调实现类对象
    private RabbitTemplate.ReturnsCallback returnsCallback;

    public void sendMessages(){
        /**
         * 确保消息发送失败后可以重新返回到队列中
         * 注意:yml需要配置 publisher-returns: true
         */
        rabbitTemplate.setMandatory(true);
        /**
         * 设置返回回调 以接收返回的消息
         */
        rabbitTemplate.setReturnsCallback(returnsCallback);
        /**
         * 设置确认回调 以接受返回的消息
         */
        rabbitTemplate.setConfirmCallback(confirmCallback);
        //构建一个消息对象
        Message message = MessageBuilder.withBody("我就是消息~".getBytes())
                //以下方法设置了 MessageProperties 的参数
                .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
                .setMessageId("123")
                .setExpiration("30000")//设置消息的过期时间
                .setPriority(10)//设置消息的优先级
                .setHeader("bar", "baz")
                .build();
        //发送消息
        for (int i=0;i<10;i++){
            rabbitTemplate.convertAndSend(BuilderAndBindings.TOPIC_EXCHANGE, "a.topicTest", message);
        }
    }
}

实现成功与失败回调

/**
 *  此类声明了 确认回调 以及 退回回调 的实现类,并实现了其中的方法,使此类用来实现消息发送确认。
 *
 *  发送消息确认:
 *      用来确认生产者 producer 将消息发送到 broker ,broker 上的交换机 exchange 再投递给队列 queue的过程中,消息是否成功投递。
 *      消息从 producer 到 rabbitmq broker有一个 confirmCallback 确认模式。
 *      消息从 exchange 到 queue 投递失败有一个 returnCallback 退回模式。
 *      我们可以利用这两个Callback来确保消息的100%送达。
 */
@Component
public class ConfirmAndReturnCallback implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {

    /**
     *  当消息被 rabbitmq broker 接收到就会触发 confirmCallback 回调 。
     *  但仅仅表示消息被 broker 接收。只能表示已经到达 MQ服务器,并不能保证
     *  消息一定会被投递到目标 queue 里。所以接下来需要用到 returnCallback 。
     *
     *
     *
     * @param correlationData 消息的唯一ID
     * @param ack 消息是否发送到 broker 的布尔值
     * @param cause 消息发送发哦 broker 失败的原因
     */

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack){
            // 消息发送到 Broker 成功
            System.out.println("消息确认发布---------------");
        }else {
            // 消息发送到 Broker 失败
            System.out.println("消息发布失败!!!!!!!!!");
        }
    }

    /**
     *  如果消息未能投递到目标 queue 里将触发回调 returnCallback ,
     *  一旦向 queue 投递消息未成功,这里一般会记录下当前消息的详细投递数据,方便后续做重发或者补偿等操作。
     *
     * @param returned 回调信息对象。包含了此次消息路由到Queue的信息
     */
    @Override
    public void returnedMessage(ReturnedMessage returned) {
        Message message = returned.getMessage();//获取消息内容
        int replyCode = returned.getReplyCode();//获取响应码
        String routingKey = returned.getRoutingKey();//获取路由Key
        String replyText = returned.getReplyText();//获取响应信息
        String exchange = returned.getExchange();//获取交换机名称

        System.out.println("消息在从 【交换机】 路由到队列时失败。失败状态码是:"+replyCode
        +"。具体消息内容是:"+new String(message.getBody())
        +"。其他信息:【路由Key】="+routingKey+"【响应信息】="+replyText+"【交换机名称】="+exchange);

    }
}

队列的知识点

队列是RabbitMQ中存储和持久化消息的重要组件,消息由交换机按照路由key的规则将消息分发到队列中进行存储,由消费者从队列中获取消息进行消费。

创建队列

队列通常由消费者处创建,使用QueueBuilder快速构建。

@Configuration
public class Queues {
    //
    @Bean("Queue_a")
     public Queue createQueue(){
        return  QueueBuilder.durable("Queue_a").build();
    }

}

不公平分发

默认情况下为公平分发采用轮询策略,公平分发可以保证服务间的压力均等,但是可能存在某些服务消费消息较慢,从而使得其他服务等待下一个消息时间过久,造成服务空档期,不公平分发设置在消费者端,以下演示开启不公平分发。

@RabbitListener(queues = "Queue_a")
public void unfair(Channel channel) throws IOException {
    /*
        请求特定的“服务质量”设置。这些设置限制了服务器在要求确认之前向消费者提供的数据量。
        因此,它们提供了一种消费者发起的流量控制方式。请注意,预取计数必须介于 0 和 65535 之间
        (AMQP 0-9-1 中的 unsigned short)。
        
       参数:prefetchSize - 服务器将传递的最大内容量(以八位字节为单位),0 如果无限制 
            prefetchCount - 服务器将传递的最大消息数,0 如果无限制
            global - 如果设置应用于整个通道则为 true,而不是每个消费者
     */
    channel.basicQos(0,0,true);
}

死信队列

死信队列用于存放在消费者无法消费的消息,在消息ttl到期、队列满载、消息被拒绝时消息将会成为死信,死信队列保证了消息无法消费时也不会丢失。消息在成为死信后由队列发送给死信交换机,再由死信交换机分发到死信队列中。

创建死信交换机与死信队列

@Configuration
public class BuilderAndBindings {

    public static final String DEAD_EXCHANGE = "dead_Exchange";
    public static final String DEAD_QUEUE = "dead_QUEUE";

    //声明死信交换机
    @Bean(DEAD_EXCHANGE)
    public Exchange createDeadExchange(){
        return ExchangeBuilder.topicExchange(DEAD_EXCHANGE).durable(true).build();
    }

    //声明死信队列
    @Bean(DEAD_QUEUE)
    public Queue createDeadQueue(){
        return QueueBuilder.durable(DEAD_QUEUE).build();
    }

    //死信绑定
    @Bean
    public Binding deadBind(@Qualifier(DEAD_EXCHANGE) Exchange e,@Qualifier(DEAD_QUEUE) Queue q){
        return BindingBuilder.bind(q).to(e).with("*.topicTest").noargs();
    }

}

在声明普通队列时将其与死信交换机进行绑定

@Bean("queueA")
public Queue queueA(){ Map args = new HashMap<>(3);
    //声明当前队列绑定的死信交换机
    args.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE); 
    //声明当前队列的死信路由 key args.put("x-dead-letter-routing-key", "YD");
    //声明队列的 TTL args.put("x-message-ttl", 10000); 
    return QueueBuilder.durable(QUEUE_A).withArguments(args).build(); 
}

消息消费者者需要设置当消息无法被消费时进入死信队列。

@Component
public class MQ_Consumer {

    @RabbitListener(queues = "topic_Queue")
    public void consumer(Message message, Channel channel){
      //在消息消费失败后,根据情况选择 直接拒绝或者拒绝后返回队列重新消费.
      /*
        deliveryTag: 该消息的序列号
        multiple: 是否批量.true:将一次性拒绝所有小于deliveryTag的消息。
        requeue: 如果被拒绝的消息应该重新排队而不是丢弃死信,则为 true
       */
      try {
          channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
      } catch (IOException e) {
          e.printStackTrace();
      }
      
      /* deliveryTag: 该消息的序列号
        requeue: 如果被拒绝的消息应该重新排队而不是丢弃死信,则为 true */
       /*
      try {
          channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
      } catch (IOException e) {
          e.printStackTrace();
      }*/
  }

惰性队列

RabbitMQ 从 3.6.0 版本开始引入了惰性队列的概念。惰性队列会尽可能的将消息存入磁盘中,而在消费者消费到相应的消息时才会被加载到内存中,它的一个重要的设计目标是能够支持更长的队列,即支持 更多的消息存储。当消费者由于各种各样的原因(比如消费者下线、宕机亦或者是由于维护而关闭等)而致 使长时间内不能消费消息造成堆积时,惰性队列就很有必要了。

队列具备两种模式:defaultlazy。默认的为 default 模式,在 3.6.0 之前的版本无需做任何变更。lazy 模式即为惰性队列的模式,

创建惰性队列

@Configuration
public class Queues {
    @Bean("Queue_a")
     public Queue createQueue(){
        return  QueueBuilder.durable("Queue_a").lazy().build();
    }
}

延迟队列

延迟队列中的消息将在指定时间后进行分发而被消费,延迟队列时有序的。

消息过期分为消息自发时就设有过期时间,和队列在声明时就设置了此队列中消息的过期时间。如果队列设置了过期时间,在此队列中过期的消息将会被丢弃(如果存在死信则会存入死信队列中),而消息本身过期将不理会被立刻丢弃,消息是否时在消息被消费之前进行判断,当过期后可能还能存活许久。如果不设置 TTL,表示消息永远不会过期,如果将 TTL 设置为 0,则表示除非此时可以 直接投递该消息到消费者,否则该消息将会被丢弃。

消息和队列两者若是都设置了过期时间则以最小的为准

延迟队列是死信队列的变种,即正常发布消息,只是将将正常的队列设置了消息的过期时间而已,在消息到达指定的时间后将被分发到死信交换机,死信交换机立刻将消息分发,从而完成消息的延迟消费。

优先级队列

优先级队列存储具有优先级的消息,将具有优先级的消息在队列中进行排队,这些消息将被优先消费。

  1. 创建具有优先级的队列
@Configuration
public class Queues {
    @Bean("Queue_a")
     public Queue createQueue(){
        return  QueueBuilder.durable("Queue_a").maxPriority(10).build();
    }
}
  1. 指定消息的优先级
@Component
public class Producer {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void send(Channel channel){
        Message message = MessageBuilder.withBody("我是消息".getBytes(StandardCharsets.UTF_8)).setPriority(5).build();
        rabbitTemplate.send("directExchange","a",message);

    }
}

持久化

  1. 队列持久化 未持久化的队列在消息被消费后将会被销毁。当RabbitMQ发生异常时,未被持久化的队列将和其中的消息都会丢失,所以应在创建队列时将队列设置为持久化队列。仅仅对队列持久化只能保证队列在RabbitMQ恢复后队列不丢失,但其中的消息将会丢失,因此在发送消息时应在消息发送者处设置为将消息也持久化到磁盘中,从而保证两者都能得到恢复。
@Configuration
public class Queues {
    @Bean("Queue_a")
     public Queue createQueue(){
        //QueueBuilder.nonDurable()为不持久化
        return  QueueBuilder.durable("Queue_a").build();
    }
}
  1. 消息持久化 消息也需要持久化,防止在RabbitMQ宕机恢复后消息丢失,持久化的消息,在被写入磁盘的同时也会在内存中驻留 一份备份。当 RabbitMQ 需要释放内存的时候,会将内存中的消息换页至磁盘中,这个操作会耗费较长的 时间,也会阻塞队列的操作,进而无法接收新的消息
//构建一个消息对象
Message message = MessageBuilder.withBody("我就是消息~".getBytes())
         //PERSISTENT 持久化
        .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
        .build();
  1. 交换机持久化 交换机同理

@Bean(topicExchange)

public Exchange createTopicExchange(){
    return ExchangeBuilder.topicExchange(TOPIC_EXCHANGE)
            .durable(true)
            .build();
}

交换机的知识点

Rabbitmq消息传递模型的核心思想是:生产者生产的消息从不会直接发送到队列。实际上,通常生产者甚至都不知道这些消息传递传递到了哪些队列中相反,生产者只能将消息发送到交换机( exchange),交换机工作的内容非常简单,一方面它接收来自生产者的消息,另一方面将它们推入队列。交换机必须确切知道如何处理收到的消息。是应该把这些消息放到特定队列还是说把他们到许多队列中还是说应该丢弃它们。这就的由交换机的类型来决定。

创建交换机

使用 ExchangeBuilder快速构建交换机

**
 * 构建交换机
 */
@Configuration
public class Exchanges {

    @Bean("directExchange")
    public Exchange createExchange(){
           //创建一个默认参数的名为 my-fanoutExchange的交换机 
        return ExchangeBuilder.fanoutExchange("my-fanoutExchange").build();

    }
}

绑定

将交换机与队列使用routingKey进行绑定,使得指定的队列只能从指定的交换机中收到消息,且制定了队列接收那些消息,当交换机接收到消息会根据routingKey和交换机与队列的绑定规则,来将消息路由到某个队列中。

@Configuration
public class BuilderAndBindings {

    @Bean
    public Binding bind(@Qualifier(TOPIC_EXCHANGE) Exchange e,@Qualifier(TOPIC_QUEUE) Queue q){
        //将交换机与队列使用*.topicTest的routingKey规则进行绑定 routingKey为 xxx.topicTest 的消息将被路由到此队列中
        return BindingBuilder.bind(q).to(e).with("*.topicTest").noargs();
    }
}

交换机的类型

不同的交换机具有不同的功能,交换机根据消息发送者们发送消息时指定的路由key来确认将此条消息发送给那条队列, 直接( direct),主题( topic),标题( headers),扇出( fanout)

1. 标题( headers)交换机

头交换机(headers exchange)使用多个消息属性来代替路由键建立路由规则。通过判断消息头的值能否与指定的绑定相匹配来确立路由规则。头交换机可以视为直连交换机的另一种表现形式。头交换机能够像直连交换机一样工作,不同之处在于头交换机的路由规则是建立在头属性值之上,而不是路由键。路由键必须是一个字符串,而头属性值则没有这个约束,它们甚至可以是整数或者哈希值(字典)等

2. 扇出( fanout)交换机

队列接收所有消息。fanout 交换机与队列不使用任何路由key进行绑定,仅仅只是简单绑定在一起,由fanout接收到的消息将全量分发到两个队列中,它只将接收到的所有消息广播到它所知道的所有队列。

image.png

3. 直接( direct)交换机

队列有选择的接收消息。直接交换机使用一个单词的路由key与多个队列绑定,直接交换机根据路由key将消息发送给队列,与绑定时使用的任何路由key都不相同的消息将被直接丢弃。

image.png

上图表示:

路由key为 orange 的消息将会被 Direct 交换机路由到与之绑定的 Q1 队列中。

路由key为black的消息将会被 Direct 交换机路由到与之绑定的 Q2 队列中。

对于Q1 队列来说他只接受所有路由key名为 orange的消息。

4. 主题( topic)交换机

队列接收拥有某些条件的消息。主题交换机根据消息发送者们发送消息时指定的路由key来讲接收到到消息分发给队列,路由key的总体必须是一组单词每个单词使用.分隔,*代表一个单词,#代表0个或者多个单词。

image.png

上图表示:

路由key为 *.orange.* 的消息将会被 Topic 交换机路由到与之绑定的 Q1 队列中。

路由key为lazy.#的消息将会被 Topic 交换机路由到与之绑定的 Q2 队列中。

对于Q1 队列来说他订阅了所有名为 *.orange.*的消息

此交换机将会将自己接收到的消息发送给与自己绑定的一个或者多个队列,队列们将都将收到交换机中的所有消息,

/**
 * 构建交换机
 */
@Configuration
public class Exchanges {
    @Bean("directExchange")
    public Exchange createExchange(){
        return ExchangeBuilder.fanoutExchange("my-fanoutExchange").build();
    }
}

消息消费者的知识点

消费消息

消费者通过监听器监听指定的队列,当队列中出现新的消息后将按照规则进行消费。

消费消息


@Component
public class MQConsumer {

    @RabbitListener(queues = "Queue_a")
    public String ConsumerMessage(Message message,Channel channel){
        try {
            // multiple: true 批量确认(应答此队列中的所有消息),false 单个确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return message.getBody().toString();
    }
}

消息应答

消息消费者负责消费指定队列中的消息,消费消息后对RabbitMQ进行应答完成消息的确认,被确认的消息将会被从队列中丢弃。应答分为两类:手动确认、自动确认。

  1. 自动确认 自动应答即为在消息发送到消费者之后无论是否被正确的消费,该消息都将被认为被消费,自动应答需要及其稳定的消息消费能力,在任何时候都需要保证消息一定会被成功消费,若果消费者某个时间段发生异常,未能正常消费消息,此时该消息已经被RabbitMQ丢弃,造成消息的丢失,通常这么做需要在效率与安全之间权衡。
spring:
  rabbitmq:
    listener:
      direct:
        acknowledge-mode:  auto  #收到消息将自动确认
  1. 手动确认
spring:
  rabbitmq:
    listener:
      direct:
        acknowledge-mode:  manual #收到消息将手动确认

重新入队

当消费者接收到消息后失去了与RabbitMQ的连接后,此条未被确认的消息将会重新排入队列中,由其他消费者消费或者等待被消费。

spring:
  rabbitmq:
    publisher-returns: true #支持消息发送失败返回队列

怎么用

使用SpringBoot操作RabbitMQ

依赖

<!--amqp是Spring中MQ中间件的抽象层,其中仅实现了对RabbtiMQ的实现-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

交换机

创建交换机以及其属性

/**
 * 构建交换机
 */
@Configuration
public class Exchanges {
    @Bean("Exchange")
    public Exchange createExchange(){
        return ExchangeBuilder
                //扇出交换机
                .fanoutExchange("交换机名称")
                 //主题交换机
                //.topicExchange()
                //标题交换机
                // .headersExchange()
                //直接交换机
                //.directExchange()

                .durable()//持久化
                .delayed()//设置延迟标志。
                .withArgument( )//添加一个参数
                .admins()//应该声明此交换的管理实例或管理 bean 名称。
                .suppressDeclaration()//切换以禁用任何管理员对交易所的声明。
                .ignoreDeclarationExceptions()//声明创建时要忽略的异常,。
                .alternate()//备用交换机
                .withArguments()//添加多个参数。
                .internal()//设置内部标志
                .autoDelete()//设置自动删除标志
                .build();
    }
}

队列

创建队列和队列设置队列的属性

/**
 * 构建队列
 */
@Configuration
public class Queues {

    public Queue createQueue(){
        return QueueBuilder.durable("queue")//自定义名称的持久化的队列(此处还有构建非持久的共4中)
                .autoDelete() //当消息发送完毕队列将被删除
                .withArguments() //手动指明队列参数与下面方法互斥

                .maxLength()//在开始丢弃队列之前设置队列中允许的(就绪)消息的数量
                 //优先级队列
                .maxPriority()//设置队列支持的优先级的最大数量;如果未设置,队列将不支持消息优先级。

                .exclusive()//最后的队列将是独占的,仅由一个连接使用,当连接关闭时队列将被删除。
                //惰性队列
                .lazy()//将队列设置为惰性模式,在磁盘上保留尽可能多的消息以减少代理的 RAM 使用。如果未设置,队列将保留内存缓存以尽可能快地传递消息

                .quorum()//设置队列参数以声明类型为“quorum”而不是“经典”的队列

                .overflow(QueueBuilder.Overflow.dropHead)//设置当最大消息或超出最大消息大小时新的消息将如何处理(dropHead丢弃最老的消息,rejectPublish拒绝新消息)

                .ttl()//设置消息的生存时间,在此之后它将被丢弃或路由到死信交换
                .deadLetterRoutingKey()//设置在将过期或被拒绝的消息路由到死信交换时使用的路由键

                .masterLocator()//设置主定位器模式,该模式确定队列主控将位于节点集群上的哪个节点。
                .expires()//设置队列在被删除之前可以保持未使用状态的时间

                .maxLengthBytes()//在开始删除队列之前设置队列中允许的总聚合体大小。

                .singleActiveConsumer()//设置“x-single-active-consumer”队列参数。
                .deliveryLimit()//设置交货限制;仅适用于quorum 队列。
    }
}

yaml配置

```
spring:
  rabbitmq:
    port: 5672
    host: 192.168.124.132
    password: root
    username: root
    addresses: localhost:5679 #客户端应连接的地址的逗号分隔列表。设置后,忽略主机和端口
    virtual-host: /
    publisher-returns: true  #支持消息发送失败返回队列
    publisher-confirm-type: correlated  #消息发布确认类型。
    connection-timeout:  #连接超时。将其设置为零以永久等待
    dynamic: true  #是否创建 AmqpAdmin bean
    listener:
      type: direct   #侦听器容器类型
      direct:
        acknowledge-mode:  auto #容器的确认方式
        auto-startup: true  #是否在启动时自动启动容器
        consumers-per-queue:  #每个队列的消费者数量
        default-requeue-rejected:  #true 默认情况下是否重对被拒绝的消息重新排队
        idle-event-interval:  #应该多久发布一次空闲容器事件
        missing-queues-fatal: true   #容器声明的队列在broker上不可用时是否失败
        prefetch:   #每个消费者可以处理的未确认消息的最大数量
        retry:
          enabled: true   #开启消费者进行重试
          initial-interval:   #第一次和第二次尝试传递消息之间的持续时间。
          max-attempts:   #尝试传递消息的最大次数
          max-interval:   #尝试之间的最长持续时间
          multiplier:   #应用于前一个重试间隔的乘数
          stateless:   #true 重试是无状态的还是有状态的。
      simple:
        concurrency:   #侦听器调用者线程的最小数量
        acknowledge-mode: auto   #容器的确认方式。
        auto-startup: true   #是否在启动时自动启动容器。
        batch-size:   #批量大小,表示为容器要使用的物理消息的数量
        default-requeue-rejected: true #默认情况下是否重对被拒绝的消息重新排队
        idle-event-interval:   #应该多久发布一次空闲容器事件
        max-concurrency:   #侦听器调用程序线程的最大数量
        missing-queues-fatal: true   #如果容器声明的队列在代理上不可用,是否失败,或者如果在运行时删除一个或多个队列,是否停止容器。
        prefetch:   #每个消费者可以处理的未确认消息的最大数量
        retry:
          enabled: true   #是否启用发布重试
          initial-interval:   #第一次和第二次尝试传递消息之间的持续时间
          max-attempts:   #尝试传递消息的最大次数
          max-interval:   #尝试之间的最长持续时间
          multiplier:   #应用于前一个重试间隔的乘数
          stateless: true   #重试是无状态的还是有状态的。
    cache:
      channel:
        checkout-timeout:   #,则等待获取通道的持续时间。如果为 0,则始终创建一个新通道
        size:   #要保留在缓存中的通道数。当“check-timeout”> 0 时,每个连接的最大通道数
      connection:
        mode: channel   #连接工厂缓存模式
        size:   #要缓存的连接数。仅在模式为 CONNECTION 时适用
    requested-channel-max:   #客户端请求的每个连接的通道数。使用 0 表示无限制
    requested-heartbeat:   #请求的心跳超时;零为无。如果没有指定持续时间后缀,将使用秒
    template:
      default-receive-queue:  #当没有明确指定时接收消息的默认队列的名称
      exchange:   #用于发送操作的默认交换器的名称
      mandatory: true   #是否启用强制消息
      receive-timeout:   #`receive()` 操作超时
      reply-timeout:   #`sendAndReceive()` 操作超时
      retry:
        enabled: true   #是否启用发布重试
        initial-interval:   #第一次和第二次尝试传递消息之间的持续时间
        max-attempts:   #尝试传递消息的最大次数
        max-interval:   #尝试之间的最长持续时间
        multiplier:  #应用于前一个重试间隔的乘数
      routing-key:    #用于发送操作的默认路由键的值
    ssl:
      algorithm:   #要使用的 SSL 算法。默认情况下,由 Rabbit 客户端库配置
      enabled: true   #是否启用 SSL 支持。如果协议提供了地址,则自动确定(amqp: vs. amqps:)
      key-store:   #保存 SSL 证书的密钥库的路径。
      key-store-password:   #用于访问密钥库的密码
      key-store-type:   #密钥库类型
      trust-store:   #持有 SSL 证书的信任库。
      trust-store-password:   #用于访问信任库的密码。
      trust-store-type:   #信任存储类型
      validate-server-certificate: true   #是否启用服务器端证书验证
      verify-hostname: true   #是否启用主机名验证
```