在之前的消息 订阅/发布 模式中已经实现了通过 Fanout 来向所有的接受者广播,在 routing 中就是在 订阅/发布 中增加指定发送的 routing key 即可。下面的图也来自于官方的实例,Q1 和 Q2 绑定到了 X 的交换机上边,Q1 绑定了 orage 的 routing key ,Q2 绑定了 black 和 green 两个 routing key。这样在 p 使用 routing key 为 orange 发送时只有 Q1 会接收到消息。Q2 会将此消息抛弃。
使用 Java 来实现 发送者 和 接收者
-
第一步当然还是导入 Maven 坐标。
<!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --> <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.9.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.25</version> <!-- <scope>test</scope>--> </dependency>
-
创建发送者端
private static final String EXCHANGE_NAME = "logs_routing"; public static void main(String[] args) { 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(); // 创建交换机 此处不能用 FANOUT 作为交换机的类型了 ,需要换成 DIRECT channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT, true, false, false, null); // 声明两个队列 channel.queueDeclare("log_fanout_queue1", false, false, false, null); channel.queueDeclare("log_fanout_queue2", false, false, false, null); // 绑定两个队列 (此处必须要要指定 routingkey) // 队列1只接收 info channel.queueBind("log_fanout_queue1", EXCHANGE_NAME, "info"); // 队列2接收所有 channel.queueBind("log_fanout_queue2", EXCHANGE_NAME, "info"); channel.queueBind("log_fanout_queue2", EXCHANGE_NAME, "warn"); channel.queueBind("log_fanout_queue2", EXCHANGE_NAME, "error"); String message = "[日志][支付信息][订单号:" + new Date().getTime() + "][支付ID:10]"; // 由于要使用 routing 模式发送所以就需要执行 routingkey channel.basicPublish(EXCHANGE_NAME, "info", null, message.getBytes(StandardCharsets.UTF_8)); channel.basicPublish(EXCHANGE_NAME, "error", null, message.getBytes(StandardCharsets.UTF_8)); // 释放资源 channel.close(); connection.close(); } catch (IOException | TimeoutException e) { e.printStackTrace(); } }
-
创建第一个接受者
private static final String EXCHANGE_NAME = "logs_routing"; public static void main(String[] args) { 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.DIRECT, true, false,false, null); String queue1Name = "log_direct_queue1"; DeliverCallback deliverCallback = (consumerTag, delivery) -> { String message = new String(delivery.getBody(), StandardCharsets.UTF_8); System.out.println(" [info] Received '" + message + "'"); }; channel.basicConsume(queue1Name, true, deliverCallback, consumerTag -> { }); } catch (IOException | TimeoutException e) { e.printStackTrace(); } }
-
创建第二个接受者
private static final String EXCHANGE_NAME = "logs_routing"; public static void main(String[] args) { 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.DIRECT, true, false,false, null); String queue1Name = "log_direct_queue2"; DeliverCallback deliverCallback = (consumerTag, delivery) -> { String message = new String(delivery.getBody(), StandardCharsets.UTF_8); System.out.println(" [info,error,warn] Received '" + message + "'"); }; channel.basicConsume(queue1Name, true, deliverCallback, consumerTag -> { }); } catch (IOException | TimeoutException e) { e.printStackTrace(); } }
在发送者发送消息到指定的队列这时候两个接受者返回的消息为
通过查看以上代码可以看出这个和 pub/sub 方式是一样,只不过是把广播模式切换成了指定方向的发送。然后在通道上绑定队列的时候要指定 routingKey 即可。