消息中间件-RabbitMQ

RabbitMQ

优势

  • 应用解耦:提高系统容错性和可维护性
  • 异步提速:提高用户体验和系统吞吐量
  • 削峰填谷:提高系统稳定性

AMQP协议

消息中间件-RabbitMQ_第1张图片
消息中间件-RabbitMQ_第2张图片

工作队列模式

work queues

定义:一个消息最多被一个消费者消费,多个消费者对一条消息是竞争关系。

图解:p->生产者;C->消费者
消息中间件-RabbitMQ_第3张图片

应用场景:对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度。

pub/sub(发布/订阅)

定义:一个消息可以被多个消费者消费。

图解:p->生产者;X->交换机;C->消费者。
消息中间件-RabbitMQ_第4张图片

应用场景:发布订阅、广播

关键代码

//声明交换机
String exchangeName = "exchange_fanout";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT, true, false, false, null);
//声明队列
String queueName1 = "fanout1";
String queueName2 = "fanout2";
channel.queueDeclare(queueName1, true, false, false, null);
channel.queueDeclare(queueName2, true, false, false, null);
//绑定交换机与队列
channel.queueBind(queueName1, exchangeName, "");
channel.queueBind(queueName2, exchangeName, "");
//发送消息
channel.basicPublish(exchangeName, "", false, null, "hello rabbitmq".getBytes());

routing(路由模式)

定义:队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)。消息的发送方在向Exchange发送消息时,也必须指定消息的 RoutingKey。Exchange 不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey 与消息的Routing key完全—致,才会接收到消息。

图解:p->生产者;X->交换机;C->消费者。
消息中间件-RabbitMQ_第5张图片
应用场景:定制化消费消息

关键代码

//声明交换机
String exchangeName = "exchange_direct";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT, true, false, false, null);
//声明队列
String queueName1 = "direct1";
String queueName2 = "direct2";
channel.queueDeclare(queueName1, true, false, false, null);
channel.queueDeclare(queueName2, true, false, false, null);
//绑定交换机与队列
channel.queueBind(queueName1, exchangeName, "error");
        
channel.queueBind(queueName2, exchangeName, "info");
channel.queueBind(queueName2, exchangeName, "error");
channel.queueBind(queueName2, exchangeName, "warn");
//发送消息
channel.basicPublish(exchangeName, "info", false, null, "hello rabbitmq".getBytes());

topic(通配符模式)

定义:使用通配符匹配

图解:p->生产者;X->交换机;C->消费者。
消息中间件-RabbitMQ_第6张图片
关键代码

//声明交换机
String exchangeName = "exchange_topic";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC, true, false, false, null);
//声明队列
String queueName1 = "topic1";
String queueName2 = "topic2";
channel.queueDeclare(queueName1, true, false, false, null);
channel.queueDeclare(queueName2, true, false, false, null);
//绑定交换机与队列
channel.queueBind(queueName1, exchangeName, "*.error");
        
channel.queueBind(queueName1, exchangeName, "order.*");
channel.queueBind(queueName2, exchangeName, "*.*");
//发送消息
channel.basicPublish(exchangeName, "order.error", false, null, "hello rabbitmq".getBytes());

死信队列

定义

由于异常情况,无法被消费的消息,延迟消费。

来源

  • 消息TTL
  • 消息被拒
  • 队列已满

图解

消息中间件-RabbitMQ_第7张图片

场景

1、TTL

消息过期成为死信

configuration

@Configuration
public class DeadLetterConfig {
    public static final String NORMAL_EXCHANGE = "normal_exchange";//普通交换机
    public static final String DEAD_EXCHANGE = "dead_exchange";//死信交换机

    public static final String NORMAL_QUEUE = "normal_queue";//普通队列
    public static final String DEAD_QUEUE = "dead_queue";//死信队列

    public static final String NORMAL_ROUTING = "normal_routing";//普通routingKey
    public static final String DEAD_ROUTING = "dead_routing";//死信routingKey

    @Bean
    public Exchange normalExchange() {//普通交换机
        return ExchangeBuilder.directExchange(NORMAL_EXCHANGE).durable(true).build();
    }

    @Bean
    public Exchange deadExchange() {//死信交换机
        return ExchangeBuilder.directExchange(DEAD_EXCHANGE).durable(true).build();
    }

    @Bean
    public Queue normalQueue() {//普通队列
        return QueueBuilder.durable(NORMAL_QUEUE)
                .deadLetterExchange(DEAD_EXCHANGE)//死信交换机
                .deadLetterRoutingKey(DEAD_ROUTING)//死信routingKey
                .build();
    }

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

    @Bean
    public Binding bindingNormalQueueExchange(@Qualifier("normalExchange") Exchange normalExchange,
                                              @Qualifier("normalQueue") Queue normalQueue) {
        return BindingBuilder
                .bind(normalQueue)
                .to(normalExchange)
                .with(NORMAL_ROUTING)
                .noargs();
    }

    @Bean
    public Binding bindingDeadQueueExchange(@Qualifier("deadExchange") Exchange deadExchange,
                                            @Qualifier("deadQueue") Queue deadQueue) {
        return BindingBuilder
                .bind(deadQueue)
                .to(deadExchange)
                .with(DEAD_ROUTING)
                .noargs();
    }
}

生产者

@RestController
public class MessageController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/message/send")
    public String send(String info) {
        rabbitTemplate.convertAndSend(
                DeadLetterConfig.NORMAL_EXCHANGE,//普通交换机
                DeadLetterConfig.NORMAL_ROUTING,//普通routingKey
                info,//消息
                mp -> {
                	//20s未被消费送到死信队列
                    mp.getMessageProperties().setExpiration("20000");
                    return mp;
                });
        return "send success";
    }
}

消费者

@Component
public class MessageListener {

    @RabbitListener(queues = "dead_queue")
    public void deadQueue(Message message){//死信队列监听器
        System.out.println("dead message "+new String(message.getBody()));
    }

    @RabbitListener(queues = "normal_queue")
    public void normalQueue(Message message){普通队列监听器
        System.out.println("normal message "+new String(message.getBody()));
    }
}

2、队列已满

超出队列容量的消息成为死信

configuration

@Configuration
public class DeadLetterConfig {
    public static final String NORMAL_EXCHANGE = "normal_exchange";//普通交换机
    public static final String DEAD_EXCHANGE = "dead_exchange";//死信交换机

    public static final String NORMAL_QUEUE = "normal_queue";//普通队列
    public static final String DEAD_QUEUE = "dead_queue";//死信队列

    public static final String NORMAL_ROUTING = "normal_routing";//普通routingKey
    public static final String DEAD_ROUTING = "dead_routing";//死信routingKey

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

    @Bean
    public Exchange deadExchange() {
        return ExchangeBuilder.directExchange(DEAD_EXCHANGE).durable(true).build();
    }

    @Bean
    public Queue normalQueue() {
        return QueueBuilder.durable(NORMAL_QUEUE)
                .deadLetterExchange(DEAD_EXCHANGE)//死信交换机
                .deadLetterRoutingKey(DEAD_ROUTING)//死信RoutingKey
                .maxLength(6)//队列最大长度为6
                .build();
    }

    @Bean
    public Queue deadQueue() {
        return QueueBuilder.durable(DEAD_QUEUE).build();
    }

    @Bean
    public Binding bindingNormalQueueExchange(@Qualifier("normalExchange") Exchange normalExchange,
                                              @Qualifier("normalQueue") Queue normalQueue) {
        return BindingBuilder
                .bind(normalQueue)
                .to(normalExchange)
                .with(NORMAL_ROUTING)
                .noargs();
    }

    @Bean
    public Binding bindingDeadQueueExchange(@Qualifier("deadExchange") Exchange deadExchange,
                                            @Qualifier("deadQueue") Queue deadQueue) {
        return BindingBuilder
                .bind(deadQueue)
                .to(deadExchange)
                .with(DEAD_ROUTING)
                .noargs();
    }
}

生产者

@RestController
public class MessageController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/message/sendMaxLength")
    public String sendMaxLength(String info) {
        for (int i = 1; i <= 10; i++) {//生产10条消息
            rabbitTemplate.convertAndSend(
                    DeadLetterConfig.NORMAL_EXCHANGE,
                    DeadLetterConfig.NORMAL_ROUTING,
                    info + i
            );
        }
        return "success";
    }
}

消费者与TTL一致,记得需要删除mq中的queue

消息中间件-RabbitMQ_第8张图片

3、消息被拒

消息被拒成为死信

configuration

@Configuration
public class DeadLetterConfig {
    public static final String NORMAL_EXCHANGE = "normal_exchange";//普通交换机
    public static final String DEAD_EXCHANGE = "dead_exchange";//死信交换机

    public static final String NORMAL_QUEUE = "normal_queue";//普通队列
    public static final String DEAD_QUEUE = "dead_queue";//死信队列

    public static final String NORMAL_ROUTING = "normal_routing";//普通routingKey
    public static final String DEAD_ROUTING = "dead_routing";//死信routingKey

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

    @Bean
    public Exchange deadExchange() {
        return ExchangeBuilder.directExchange(DEAD_EXCHANGE).durable(true).build();
    }

    @Bean
    public Queue normalQueue() {
        return QueueBuilder.durable(NORMAL_QUEUE)
                .deadLetterExchange(DEAD_EXCHANGE)//死信交换机
                .deadLetterRoutingKey(DEAD_ROUTING)//死信RoutingKey
                .build();
    }

    @Bean
    public Queue deadQueue() {
        return QueueBuilder.durable(DEAD_QUEUE).build();
    }

    @Bean
    public Binding bindingNormalQueueExchange(@Qualifier("normalExchange") Exchange normalExchange,
                                              @Qualifier("normalQueue") Queue normalQueue) {
        return BindingBuilder
                .bind(normalQueue)
                .to(normalExchange)
                .with(NORMAL_ROUTING)
                .noargs();
    }

    @Bean
    public Binding bindingDeadQueueExchange(@Qualifier("deadExchange") Exchange deadExchange,
                                            @Qualifier("deadQueue") Queue deadQueue) {
        return BindingBuilder
                .bind(deadQueue)
                .to(deadExchange)
                .with(DEAD_ROUTING)
                .noargs();
    }
}

生产者

@RestController
public class MessageController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/message/sendRejected")
    public String sendRejected(String info) {
        for (int i = 1; i <= 10; i++) {
            rabbitTemplate.convertAndSend(
                    DeadLetterConfig.NORMAL_EXCHANGE,
                    DeadLetterConfig.NORMAL_ROUTING,
                    info + i
            );
        }
        return "success";
    }
}

消费者

@Component
public class MessageListener {

    @RabbitListener(queues = "boot_queue")
    public void bootQueue(Message message) {
        System.out.println(message.getBody());
    }

    @RabbitListener(queues = "dead_queue")
    public void deadQueue(Message message) {
        System.out.println("dead message " + new String(message.getBody()));
    }

    @RabbitListener(queues = "normal_queue")
    public void normalQueue(Message message, Channel channel) throws IOException {
        if ("oxx5".equals(new String(message.getBody()).intern())) {
            //消息被拒,false代表成为死信
            channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
        } else {
            //自动确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);
        }
    }
}

延迟队列

定义

相当于消息TTL过期

场景

  • 订单在十分钟之内未支付则自动取消。
  • 新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒。
  • 用户注册成功后,如果三天内没有登陆则进行短信提醒。
  • 用户发起退款,如果三天内没有得到处理则通知相关运营人员。
  • 预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议。

案例

创建两个队列QA和QB,两者队列TTL分别设置为10s和40s,然后在创建一个交换机X和死信交换机Y,它们的类型都是direct,创建一个死信队列QD。
消息中间件-RabbitMQ_第9张图片
configuration

@Configuration
public class TTLDeadLetterConfig {
    public static final String NORMAL_EXCHANGE = "normal_exchange";//普通交换机
    public static final String DEAD_EXCHANGE = "dead_exchange";//死信交换机

    public static final String NORMAL_QUEUE_A = "normal_queue_a";//普通队列A
    public static final String NORMAL_QUEUE_B = "normal_queue_b";//普通队列B
    public static final String DEAD_QUEUE = "dead_queue";//死信队列

    public static final String NORMAL_ROUTING_KEY_A = "normal_routing_key_a";//routingKeyA
    public static final String NORMAL_ROUTING_KEY_B = "normal_routing_key_b";//routingKeyB
    public static final String DEAD_ROUTING_KEY = "dead_routing_key";//死信routingKey

    //声明交换机
    @Bean
    public Exchange normalExchange(){//普通交换机
        return ExchangeBuilder.directExchange(NORMAL_EXCHANGE).durable(true).build();
    }

    @Bean
    public Exchange deadExchange(){//死信交换机
        return ExchangeBuilder.directExchange(DEAD_EXCHANGE).durable(true).build();
    }

    //声明队列
    @Bean
    public Queue normalQueueA(){//普通队列A
        return QueueBuilder.durable(NORMAL_QUEUE_A)
                .deadLetterExchange(DEAD_EXCHANGE)//死信交换机
                .deadLetterRoutingKey(DEAD_ROUTING_KEY)//死信routingKey
                .ttl(10000)//过期时间10s
                .build();
    }
    @Bean
    public Queue normalQueueB(){//普通队列B
        return QueueBuilder.durable(NORMAL_QUEUE_B)
                .deadLetterExchange(DEAD_EXCHANGE)//死信交换机
                .deadLetterRoutingKey(DEAD_ROUTING_KEY)//死信routingKey
                .ttl(40000)//过期时间40s
                .build();
    }

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

    //队列与交换机绑定
    @Bean
    public Binding bindingExchangeNormalA(
            @Qualifier("normalExchange") Exchange normalExchange,
            @Qualifier("normalQueueA") Queue normalQueueA){
        return BindingBuilder.bind(normalQueueA).to(normalExchange).with(NORMAL_ROUTING_KEY_A).noargs();
    }

    @Bean
    public Binding bindingExchangeNormalB(
            @Qualifier("normalExchange") Exchange normalExchange,
            @Qualifier("normalQueueB") Queue normalQueueB){
        return BindingBuilder.bind(normalQueueB).to(normalExchange).with(NORMAL_ROUTING_KEY_B).noargs();
    }

    @Bean
    public Binding bindingExchangeDead(
            @Qualifier("deadExchange") Exchange deadExchange,
            @Qualifier("deadQueue") Queue deadQueue){
        return BindingBuilder.bind(deadQueue).to(deadExchange).with(DEAD_ROUTING_KEY).noargs();
    }
}

生产者

@RestController
@RequestMapping("/ttl")
@Slf4j
public class TTLController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/send/{message}")
    public String send(@PathVariable("message") String message) {

        log.info("send message - {}",message);

        //发送消息,10s后处理
        rabbitTemplate.convertAndSend(
                TTLDeadLetterConfig.NORMAL_EXCHANGE,//交换机
                TTLDeadLetterConfig.NORMAL_ROUTING_KEY_A,
                message
        );
        //发送消息,40后处理
        rabbitTemplate.convertAndSend(
                TTLDeadLetterConfig.NORMAL_EXCHANGE,//交换机
                TTLDeadLetterConfig.NORMAL_ROUTING_KEY_B,
                message
        );
        return "success";
    }
}

消费者

@Component
@Slf4j
public class TTLListener {

    @RabbitListener(queues = "dead_queue")
    public void ttl(Message message) {
        log.info("receive message - {}",new String(message.getBody()));
    }
}

上述案例有个缺点,每新增一个ttl,需要新增一个普通队列,维护比较困难。

优化

  • 不给普通队列设置ttl,在生产端动态设置过期时间
  • 延迟插件

不基于插件
消息中间件-RabbitMQ_第10张图片

消息中间件-RabbitMQ_第11张图片

基于插件
消息中间件-RabbitMQ_第12张图片

消息中间件-RabbitMQ_第13张图片

代码

configuration

@Controller
public class DelayConfig {
    public static final String DELAY_EXCHANGE = "delay_exchange";//延迟交换机
    public static final String DELAY_QUEUE = "delay_queue";//延迟队列
    public static final String DELAY_ROUTING_KEY = "delay_routing_key";//延迟队列

    @Bean
    public Exchange delayExchange() {
        Map<String,Object> args = new HashMap<>();
        args.put("x-delayed-type","direct");

        return new CustomExchange(
                DELAY_EXCHANGE,
                "x-delayed-message",
                true,
                false,
                args);
    }

    @Bean
    public Queue delayQueue() {
        return QueueBuilder.durable(DELAY_QUEUE).build();
    }

    @Bean
    public Binding bindingExchangeQueue(
            @Qualifier("delayQueue") Queue queue,
            @Qualifier("delayExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(DELAY_ROUTING_KEY).noargs();
    }
}

生产者

@RestController
@RequestMapping("/ttl")
@Slf4j
public class TTLController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/send/delay/{delay}/{message}")
    public String send2(@PathVariable("delay") Integer delay, @PathVariable("message") String message) {

        log.info("send delay - {}, message - {}", delay,message);

        rabbitTemplate.convertAndSend(
                DelayConfig.DELAY_EXCHANGE,
                DelayConfig.DELAY_ROUTING_KEY,
                message,
                mp -> {
                    mp.getMessageProperties().setDelay(delay);//设置延迟时间
                    return mp;
                });
        return "success";
    }
}

消费者

@Component
@Slf4j
public class TTLListener {
    @RabbitListener(queues = "delay_queue")
    public void delay(Message message) {
        log.info("delay receive message - {}",new String(message.getBody()));
    }
}

发布确认/回退消息/备份交换机

备份交换机场景图

消息中间件-RabbitMQ_第14张图片

场景

  • 交换机出现故障 —— 发布确认
  • 交换机正常,队列不存在(异常,消息不可路由)—— 消息回退/备份交换机
  • 用于监测与报警 —— 备份交换机

当备份交换机和消息回退同时存在时,以备份交换机为主
备份交换机类型为 fanout

代码

application.yml

spring:
  rabbitmq:
  	publisher-confirm-type: correlated #开启发布确认模式
  	publisher-returns: true #消息回退

configuration

@Configuration
public class ConfirmConfig {
    public static final String CONFIRM_EXCHANGE = "confirm_exchange";//确认交换机
    public static final String CONFIRM_QUEUE = "confirm_queue";//确认队列
    public static final String CONFIRM_ROUTING_KEY = "confirm_routing_key";//确认routingKey

    public static final String ALTERNATE_EXCHANGE = "alternate_exchange";//备份交换机
    public static final String ALTERNATE_QUEUE = "alternate_queue";//备份队列(报警队列)
    public static final String ALTERNATE_ROUTING_KEY = "alternate_routing_key";//备份routingKey

    @Bean
    public Exchange confirmExchange() {
        return ExchangeBuilder.
                directExchange(CONFIRM_EXCHANGE).
                durable(true).
                alternate(ALTERNATE_EXCHANGE).//备份交换机
                build();
    }

    @Bean
    public Exchange alternateExchange(){
        return ExchangeBuilder.fanoutExchange(ALTERNATE_EXCHANGE).durable(true).build();
    }

    @Bean
    public Queue confirmQueue() {
        return QueueBuilder.durable(CONFIRM_QUEUE).build();
    }

    @Bean
    public Queue alternateQueue() {
        return QueueBuilder.durable(ALTERNATE_QUEUE).build();
    }

    @Bean
    public Binding bindingExchangeQueue(
            @Qualifier("confirmQueue") Queue queue,
            @Qualifier("confirmExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(CONFIRM_ROUTING_KEY).noargs();
    }

    @Bean
    public Binding bindingExchangeWarnQueue(
            @Qualifier("alternateQueue") Queue queue,
            @Qualifier("alternateExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ALTERNATE_ROUTING_KEY).noargs();
    }
}

生产者

@Slf4j
@RestController
@RequestMapping("/confirm")
public class ConfirmController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/send/{id}/{message}")
    public String send(@PathVariable("id") String id, @PathVariable("message") String message) {
        log.info("confirm message - {}", message);

        rabbitTemplate.convertAndSend(
                ConfirmConfig.CONFIRM_EXCHANGE+"1",
                ConfirmConfig.CONFIRM_ROUTING_KEY,
                message,
                new CorrelationData(id)
        );

        return "success";
    }
}

消费者

@Component
@Slf4j
public class ConfirmListener {

    @RabbitListener(queues = "confirm_queue")
    public void confirm(Message message) {//确认队列
        log.info("confirm message - {}", message);
    }

    @RabbitListener(queues = "alternate_queue")
    public void warn(Message message) {//备份队列
        log.info("warn message - {}", message);
    }
}

回调

public class ConfirmCallback implements 
        RabbitTemplate.ConfirmCallback,
        RabbitTemplate.ReturnsCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }

    @Override
    public void confirm(
            CorrelationData correlationData, //消息
            boolean ack, //是否确认
            String cause//产生原因
    ) {//确认消息
        String id = correlationData.getId();
        if (ack) {//正常接收消息
            log.info("id - {}", id);
        } else {//交换机异常
            log.info("no adapter exchange,cause - {}", cause);
        }
    }

    @Override
    public void returnedMessage(ReturnedMessage rm) {//回退消息
        log.info("exchange - {}",rm.getExchange());//交换机
        log.info("replyText - {}",rm.getReplyText());//回退原因
        log.info("message - {}",rm.getMessage());//回退消息
    }
}

优先级队列youxian

定义

提前消费优先级高的消息

场景

  • 提前处理VIP客户订单

代码

configuration

@Configuration
public class PriorityConfig {
    public static final String PRIORITY_EXCHANGE = "priority_exchange";//交换机
    public static final String PRIORITY_QUEUE = "priority_queue";//队列
    public static final String PRIORITY_ROUTING_KEY = "priority_routing_key";//routingKey

    @Bean
    public Exchange priorityExchange() {
        return ExchangeBuilder.directExchange(PRIORITY_EXCHANGE).durable(true).build();
    }

    @Bean
    public Queue priorityQueue() {

        return QueueBuilder
                .durable(PRIORITY_QUEUE)
                .maxPriority(10)//最大优先级
                .build();
    }

    @Bean
    public Binding bindingExchangePriorityQueue(
            @Qualifier("priorityQueue") Queue queue,
            @Qualifier("priorityExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(PRIORITY_ROUTING_KEY).noargs();
    }
}

生产者

@Slf4j
@RestController
@RequestMapping("/priority")
public class PriorityController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/send/{message}")
    public String send( @PathVariable("message") String message) {
        log.info("priority message - {}", message);

        for (int i = 1; i <= 10; i++) {
            if(i == 5){
                rabbitTemplate.convertAndSend(
                        PriorityConfig.PRIORITY_EXCHANGE,
                        PriorityConfig.PRIORITY_ROUTING_KEY,
                        message + i,
                        mp -> {
                            mp.getMessageProperties().setPriority(5);//设置优先级
                            return mp;
                        }
                );
            }
            else {
                rabbitTemplate.convertAndSend(
                        PriorityConfig.PRIORITY_EXCHANGE,
                        PriorityConfig.PRIORITY_ROUTING_KEY,
                        message + i,
                        mp -> {
                            mp.getMessageProperties().setPriority(4);//设置优先级
                            return mp;
                        }
                );
            }
        }

        return "success";
    }
}

消费者

@Component
@Slf4j
public class PriorityListener {
    @RabbitListener(queues = "priority_queue")
    public void priority(Message message){
        log.info("priority message - {}",new String(message.getBody()));
    }
}

惰性队列

定义

  • 消息存放在磁盘

场景

  • 消费者宕机导致消息积压,占用内存过大

代码

configuration

@Bean
    public Queue lazyQueue() {

        return QueueBuilder
                .durable(LAZY_QUEUE)
                .lazy()
                .build();
    }

其他代码大致一样

你可能感兴趣的:(java-rabbitmq,rabbitmq,java)