在routing路由模型中,我们实现了可以根据routingKey来选择性地将消息发送到对应的消息队列中,但是,这种模型不够灵活,比如最开始只有warn、info、error、三种类型的日志,但后面如果需要增加fetal类型的日志,则需要修改原有代码,不符合开闭原则。使用topic模型可以比较好的满足这一点,支持通配符的方式来进行扩展。

依旧,我们在官方文档中可以看到详细的说明,使用*号可以代替一个单词,使用#号可以代替零个或多个单词。所以,当我想适配所有类型的routingKey时,使用#号作为routingKey即可。另外,rabbitmq官方还推荐我们使用.来连接多个单词作为routingKey。

springboot rabbitmq 一个消息多个消费_ide


老规矩,我们这次需要使用topic类型的交换机,可以使用已有的,也可以自己重新声明一个新的。

  1. 生产者
public class Provider {
    public void send() throws IOException, TimeoutException {
        Connection connection = null;
        Channel channel = null;
        try {
            connection = ConnectionUtils.getConnection();
            // 获取连接通道
            channel = connection.createChannel();
            // 定义通道对应的交换机 参数一:交换机名称 参数二:类型 direct
            channel.exchangeDeclare("amqp.topic","topic");
            String routingKey = "log.info";
            // 发送消息
            channel.basicPublish("amqp.topic",routingKey,null,("topic message,routingKey为:" + routingKey + "," + System.currentTimeMillis()).getBytes());
        }finally {
            if (channel !=null && channel.isOpen()) {
                channel.close();
            }
            if (connection != null && connection.isOpen()) {
                connection.close();
            }
        }
    }

    public static void main(String[] args) throws IOException, TimeoutException {
        Provider provider = new Provider();
        provider.send();
    }
}
  1. 消费者

消费者一

public class Consumer01 {
    public void consume() throws IOException, TimeoutException {
        Connection connection = ConnectionUtils.getConnection();
        // 获取连接通道
        final Channel channel = connection.createChannel();
        // 绑定交换机
        channel.exchangeDeclare("amqp.topic","topic");
        //创建临时队列
        String queueName = channel.queueDeclare().getQueue();
        // 绑定交换机和队列
        channel.queueBind(queueName,"amqp.topic","#");

        // 每次只能消费一个消息
        channel.basicQos(1);
        // 消费消息
        channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费消息:" + new String(body));
                //参数一:确认队列中的那个消息  参数二:是否开启多个消息同时确认
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }

    public static void main(String[] args) throws IOException, TimeoutException {
        Consumer01 consumer = new Consumer01();
        consumer.consume();
    }
}

在消费者一中我们即使用了#号作为routingKey,来接收各种类型的消息。

消费者二:

public class Consumer02 {
    public void consume() throws IOException, TimeoutException {
        Connection connection = ConnectionUtils.getConnection();
        // 获取连接通道
        final Channel channel = connection.createChannel();
        // 绑定交换机
        channel.exchangeDeclare("amqp.topic","topic");
        //创建临时队列
        String queueName = channel.queueDeclare().getQueue();
        // 绑定交换机和队列
        channel.queueBind(queueName,"amqp.topic","*.error");

        // 每次只能消费一个消息
        channel.basicQos(1);
        // 消费消息
        channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费消息:" + new String(body));
                //参数一:确认队列中的那个消息  参数二:是否开启多个消息同时确认
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }
    public static void main(String[] args) throws IOException, TimeoutException {
        Consumer02 consumer = new Consumer02();
        consumer.consume();
    }

}

消费者二中使用*号代替一个单词,接收以.error结尾的routingKey类型的消息。

  1. 测试
    启动消费者一和消费者二,再运行生产者,发送一条routingKey为log.info的消息

消费者一:

springboot rabbitmq 一个消息多个消费_发送消息_02

消费者二:

springboot rabbitmq 一个消息多个消费_ide_03

随即,我们再发送一条routingKey为file.error的消息

此时,消费者一:

springboot rabbitmq 一个消息多个消费_发送消息_04


消费者二:

springboot rabbitmq 一个消息多个消费_ide_05