RabbitMQ-备份交换机技术实战

文章目录

  • 项目结构
  • 配置类代码
  • 回调接口配置
  • 生产者代码
  • 普通队列消费者代码
  • 报警队列消费者代码
  • 备份队列消费者代码
  • 测试
  • 同系列文章
    • 原理部分
    • 操作部分

项目结构

RabbitMQ-备份交换机技术实战_第1张图片
P:生产者
confirm consumer:普通消费者
backup consumer:备份消费者
warning consumer:报警消费者
confirm.exchange:正常交换机(直连交换机)
backup.exchange:备份交换机(扇出交换机)
confirm.queue:正常队列
backup.queue:备份队列
warning.queue:报警队列

若正常交换机及队列出现问题,消息将被备用交换机接收并转发,转发到备份队列进行备份,以及转发到报警队列进行报警提醒

下面开始操作:

配置类代码

/**
 * 配置类 发布确认
 */
@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_EXCHANGE_ROUTING_KEY="key1";
    //备份交换机
    public static final String BACKUP_EXCHANGE_NAME="backup_exchange";
    //备份队列
    public static final String BACKUP_QUEUE_NAME="backup_queue";
    //报警队列
    public static final String WARNING_QUEUE_NAME="warning_queue";

    //声明普通交换机
    @Bean("confirmExchange")
    public DirectExchange confirmExchange(){
        //设置备份交换机转发
        return ExchangeBuilder.directExchange(CONFIRM_EXCHANGE_NAME).durable(true)
                .withArgument("alternate-exchange",BACKUP_EXCHANGE_NAME).build();
    }
    
    //声明普通队列
    @Bean("confirmQueue")
    public Queue confirmQueue(){
        return QueueBuilder.durable(CONFIRM_QUEUE_NAME).build();
    }


    //声明备份交换机
    @Bean("backupExchange")
    public  FanoutExchange backupExchange(){
        return new FanoutExchange(BACKUP_EXCHANGE_NAME);
    }

    //声明备份队列
    @Bean("backupQueue")
    public Queue backupQueue(){
        return QueueBuilder.durable(BACKUP_QUEUE_NAME).build();
    }

    //声明报警队列
    @Bean("warningQueue")
    public Queue warningQueue(){
        return QueueBuilder.durable(WARNING_QUEUE_NAME).build();
    }

    //绑定普通交换机和普通队列
    @Bean
    public Binding queueBindingExchange(@Qualifier("confirmQueue") Queue confirmQueue,
                                        @Qualifier("confirmExchange")DirectExchange confirmExchange){
        return BindingBuilder.bind(confirmQueue).to(confirmExchange).with(CONFIRM_EXCHANGE_ROUTING_KEY);
    }

    //绑定备份交换机和备份队列
    @Bean
    public Binding backupQueueBindingBackupExchange(@Qualifier("backupQueue") Queue backupQueue,
                                        @Qualifier("backupExchange")FanoutExchange backupExchange){
        return BindingBuilder.bind(backupQueue).to(backupExchange);
    }

    //绑定备份交换机和报警队列
    @Bean
    public Binding warningQueueBindingBackupExchange(@Qualifier("warningQueue") Queue waringQueue,
                                                    @Qualifier("backupExchange")FanoutExchange backupExchange){
        return BindingBuilder.bind(waringQueue).to(backupExchange);
    }

}

消息回报和备份交换机同时配置时,默认使用备份交换机(优先级高),我们可以都配置试一下

回调接口配置

/**
 *回调接口
 */
@Slf4j
@Component
public class MyCallBack implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnsCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void init(){
        //内部接口注入类中
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }

    /**
     *交换机确定回调方法
     * 1.发消息 交换机接收到消息 回调
     *  1.1 correlationData 保存回调消息的ID及相关信息
     *  1.2 交换机收到消息 ack=true
     *  1.3 cause null
     * 2.发消息 交换机接受失败 回调
     *  2.1 correlationData 保存回调消息的ID及相关信息
     *  2.2 交换机收到消息 ack=false
     *  2.3 cause 失败原因
     */

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id = correlationData != null ? correlationData.getId() : "";
        if(ack){
            log.info("交换机已经收到id为:{}的消息",id);
        }
        else {
            log.info("交换机未经收到id为:{}的消息,原因为:{}",id,cause);
        }

    }

    //在消息传递过程中不可达目的地时将消息返回给生产者
    //只有不可达目的地时才进行回退
    @Override
    public void returnedMessage(ReturnedMessage returnedMessage) {
        log.error("消息被交换机:{}退回,路由key:{},退回原因:{}",
                returnedMessage.getExchange(), returnedMessage.getRoutingKey(),returnedMessage.getReplyText());
    }
}

生产者代码

这一次,在生产者代码中,我们发两次消息,第一次RoutingKey是正常情况(key1),第二次将RoutingKey改成错误的(key12),观察接收情况和回报信息

/**
 * 开始发消息,消息确认
 */
@Slf4j
@RestController
@RequestMapping("confirm")
public class ProduceController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMessage/{message}")
    public void sendMessage(@PathVariable String message){
        CorrelationData correlationData1 = new CorrelationData("1");
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME,
                ConfirmConfig.CONFIRM_EXCHANGE_ROUTING_KEY,message,correlationData1);
        log.info("发送的消息内容为:{}",message+"key1");

        CorrelationData correlationData2 = new CorrelationData("2");
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE_NAME,
                ConfirmConfig.CONFIRM_EXCHANGE_ROUTING_KEY+"2",message,correlationData2);
        log.info("发送的消息内容为:{}",message+"key12");
    }

}

普通队列消费者代码

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

报警队列消费者代码

/**
 * 报警队列消费者
 */
@Slf4j
@Component
public class WarningConsumer {

    @RabbitListener(queues = ConfirmConfig.WARNING_QUEUE_NAME)
    public void receiveWarningMsg(Message message){
        String msg = new String(message.getBody());
        log.error("Warning!:发现不可路由消息:{}",msg);
    }

}

备份队列消费者代码

/**
 * 备份队列消费者
 */
@Slf4j
@Component
public class BackupConsumer {

    @RabbitListener(queues = ConfirmConfig.BACKUP_QUEUE_NAME)
    public void receiveWarningMsg(Message message){
        String msg = new String(message.getBody());
        log.info("备份消息:{}",msg);
    }

}

测试

RabbitMQ-备份交换机技术实战_第2张图片
RabbitMQ-备份交换机技术实战_第3张图片
交换机都收到消息,key1路径的消息正常被消费者消费,key12路径的消息找不到对应的队列,被转发到报警和备份队列中,此时消息回报功能不生效

同系列文章

原理部分

MQ(消息队列)简介
RabbitMQ简介
RabbitMQ 四大核心概念及工作原理

操作部分

Windows版Docker安装RabbitMq
Maven整合RabbitMQ实现生产消费消息
SpringBoot整合RabbitMQ实现生产消费消息
RabbitMQ延迟队列及实战
RabbitMQ发布确认-交换机确认
RabbitMQ-消息回报(队列确认)
RabbitMQ-优先级队列

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