java实现rabbitmq路由模型(routing/topic queues), 生产者 消费者 交换机 消息队列

在fanout模型中,一条休息会被所有订阅的队列消费,及绑定了对应交换机的消费者,都能收到消息。但在某些场景下,我们希望不同的消息发送到不同的队列,被不同的霞飞这消费,此时就要用到Direct类型的交换机。比如日志分为warn、info、error等多个类型,在错误日志中,只需要看到error类型的日志,在所有日志中,多个类型的日志都需要被记录

在官方文档可以看到,我们给发送的消息一个绑定键,即秘钥,队列在接收消息时需要匹配对应的绑定建,符合自己规则的消息才会接收。

在这里插入图片描述

  1. 生产者
    首先,我们要选择direct类型的交换机,此时,我的/vh虚拟主机默认提供了一个名为amq.direct的direct类型的交换机,我们不妨重新声明一个amqp.direct的direct类型的交换机,与之前例子的交换机相呼应。
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.direct","direct");
            String routingKey = "info";
            // 发送消息
            channel.basicPublish("amqp.direct",routingKey,null,("direct 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();
    }
}

在执行生产者后,因为原交换机列表中不存在代码中的交换机,rabbitmq会自动创建一个对应的交换机。

  1. 消费者

消费者一:

public class Consumer01 {
    
    
    public void consume() throws IOException, TimeoutException {
    
    
        Connection connection = ConnectionUtils.getConnection();
        // 获取连接通道
        final Channel channel = connection.createChannel();
        // 绑定交换机
        channel.exchangeDeclare("amqp.direct","direct");
        //创建临时队列
        String queueName = channel.queueDeclare().getQueue();
        // 绑定交换机和队列
        channel.queueBind(queueName,"amqp.direct","info");
        channel.queueBind(queueName,"amqp.direct","warn");
        channel.queueBind(queueName,"amqp.direct","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 {
    
    
        Consumer01 consumer = new Consumer01();
        consumer.consume();
    }
}

消费者二:

public class Consumer02 {
    
    
    public void consume() throws IOException, TimeoutException {
    
    
        Connection connection = ConnectionUtils.getConnection();
        // 获取连接通道
        final Channel channel = connection.createChannel();
        // 绑定交换机
        channel.exchangeDeclare("amqp.direct","direct");
        //创建临时队列
        String queueName = channel.queueDeclare().getQueue();
        // 绑定交换机和队列
        channel.queueBind(queueName,"amqp.direct","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();
    }

}

在消费者一中绑定了info、warn、error三种routingKey,在消费者二中绑定了error一种routingKey

  1. 测试
    启动消费者一和消费者二,再启动生产者,发送一条info类型的消息。

此时:
消费者一
在这里插入图片描述
消费者二
在这里插入图片描述可见,消费者一接收到了消息,而消费者二并没有接收到
我们再发送一条error类型的消息。

此时:
消费者一
在这里插入图片描述消费者二
在这里插入图片描述消费者一和二都接受到了这条routingKey为error的消息,以此,可以根据routingKey来控制哪些消息发送给哪些队列。

猜你喜欢

转载自blog.csdn.net/qq_41885819/article/details/112882630