RabbitMQ 六种基本队列模式 ----- 消息订阅(Publish/Subscribe)


我们将向多个消费者传递一条信息。这种模式称为“发布/订阅”

**在之前的文章 P 和 C 已经很清楚是什么意思了,这里面的X代表的是交换机(Exchange)。交换机只负责转发消息,不具有存储消息的能力,因此如果没有队列与交换机绑定,或者没有符合规则的队列,那么消息就会丢失**

交换机的类型

  • Fanout: 广播,发送到每个与交换机绑定的队列
  • Direct: 定向
  • Topic: 通配符
  • Headers: 参数匹配

使用 java 来实现简单的 Publish/Subscribe

  • 导入 Maven 坐标

    
    
        com.rabbitmq
        amqp-client
        5.9.0
    
    
    
    
        org.slf4j
        slf4j-simple
        1.7.25
    
    
    
  • 编写 Publish 端代码

    public static void main(String[] args) {
            final String EXCHANGE_NAME = "logs";
            try {
                ConnectionFactory factory = new ConnectionFactory();
                // 设置参数
                factory.setHost("192.168.3.64");
                factory.setPort(5672);
                factory.setVirtualHost("/default_virtual_host");
                factory.setUsername("admin");
                factory.setPassword("admin");
    
                Connection connection = factory.newConnection();
                Channel channel = connection.createChannel();
                // 创建交换机
                channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT, true, false, false, null);
                // 创建队列
                channel.queueDeclare("log_fanout_queue1", false, false, false, null);
                channel.queueDeclare("log_fanout_queue2", false, false, false, null);
                // 绑定队列
                channel.queueBind("log_fanout_queue1", EXCHANGE_NAME, "");
                channel.queueBind("log_fanout_queue2", EXCHANGE_NAME, "");
                // 发送消息
                String message = "[日志][支付信息][订单号:" + new Date().getTime() +"][支付ID:10]";
                channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes(StandardCharsets.UTF_8));
                // 释放资源
                channel.close();
                connection.close();
    
            } catch (IOException | TimeoutException e) {
                e.fillInStackTrace();
            }
        }
    
  • 编写第一个 Subscribe 端代码

    public static void main(String[] args) {
            final String EXCHANGE_NAME = "logs";
    
            try {
                ConnectionFactory factory = new ConnectionFactory();
                // 设置参数
                factory.setHost("192.168.3.64");
                factory.setPort(5672);
                factory.setVirtualHost("/default_virtual_host");
                factory.setUsername("admin");
                factory.setPassword("admin");
    
                Connection connection = factory.newConnection();
                Channel channel = connection.createChannel();
    
                channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT, true, false, false, null);
    
                String queue1Name = "log_fanout_queue1";
    
    //            channel.queueBind(queue1Name, EXCHANGE_NAME, "");
    
                DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                    String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
                    System.out.println(" [x] Received '" + message + "'");
                };
                channel.basicConsume(queue1Name, true, deliverCallback, consumerTag -> {
                });
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
        }
    
  • 编写第二个 Subscribe 端代码

    
    public static void main(String[] args) {
            final String EXCHANGE_NAME = "logs";
    
            try {
                ConnectionFactory factory = new ConnectionFactory();
                // 设置参数
                factory.setHost("192.168.3.64");
                factory.setPort(5672);
                factory.setVirtualHost("/default_virtual_host");
                factory.setUsername("admin");
                factory.setPassword("admin");
    
                Connection connection = factory.newConnection();
                Channel channel = connection.createChannel();
    
                channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT, true, false, false, null);
    
                String queue2Name = "log_fanout_queue2";
    
    //            channel.queueBind(queue2Name, EXCHANGE_NAME, "");
    
                DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                    String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
                    System.out.println(" [x] Received '" + message + "'");
                };
                channel.basicConsume(queue2Name, true, deliverCallback, consumerTag -> {
                });
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
        }
    
  • 启动消费者和生产者

    • 消息队列展示

    • 消费者接收到的消息