前言
在上一个教程中,我们构建了一个简单的日志记录系统。我们能够向许多接收者广播日志消息。
在本教程中,我们将向其中添加功能-我们将使仅订阅消息的子集成为可能。例如,我们将只能将严重错误消息定向到日志文件(以节省磁盘空间),同时仍然能够在控制台上打印所有日志消息。
在前面的示例中,我们已经创建绑定,比如
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,“”);
绑定是交换和队列之间的关系。可以简单地理解为:队列对来自此交换的消息感兴趣。绑定可以采用额外的routing Key参数,避免与basic_publish参数混淆,我们称为binding_key(绑定密钥)。
直接交换
上一教程中的日志系统将所有消息广播给所有使用者。我们想要扩展它以允许根据邮件的严重性过滤邮件。例如,我们可能希望将日志消息写入磁盘的程序仅接收严重错误,而不会在警告或信息日志消息上浪费磁盘空间。我们使用的是fanout(扇型)交换,这种交换并没有给我们带来太大的灵活性-它只能进行无意识的广播。
我们将使用direct交换。direct交换背后的路由算法很简单-消息进入binding_key(绑定密钥)与消息的routing key(路由密钥)完全匹配的队列 。
为了说明这一点,请考虑以下设置:
在此设置中,我们可以看到绑定了两个队列的direct交换,第一个队列绑定键为orange,第二个绑定键为两个,一个绑定键为black,另一个绑定键为green。
在这种设置中,使用路由键orange发布到交换机的消息 将被路由到队列Q1。路由键为black 或为green 将转到Q2,所有其他消息将被丢弃。
多重绑定
在这种设置中,用相同的绑定密钥绑定多个队列也是完全可以的,类似为订阅模式,将消息广播到所有匹配的队列,同时发送到Q1 和 Q2中。
绑定类型
channel.exchangeDeclare(EXCHANGE_NAME,“direct”);
一、引入RabbitMQ的开发包
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.6</version>
</dependency>
二、连接工具
package com.example.demo.util;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 消息队列连接工具
*
*/
public class MQConnectionUtils {
public static Connection connection() throws IOException, TimeoutException{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setUsername("guest");
factory.setPassword("guest");
factory.setPort(5672);
return factory.newConnection();
}
}
三、生产者
package com.example.demo.produce;
import com.example.demo.util.MQConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 路由模式 - 生产者
*
*/
public class RouteProduce {
private static final String EXCHANGE_NAME = "my_exchange_route";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = MQConnectionUtils.connection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String msg = "", type = "";
for (int i = 0; i < 20; i++){
if ((i % 2) == 0){
type = "error";
msg = "hello,我是路由模式,消息类型为error:" + (i+1);
}else {
type = "info";
msg = "hello,我是路由模式,消息类型为info:" + (i+1);
}
try {
Thread.sleep(1000);
}catch (Exception r){
r.printStackTrace();
}
channel.basicPublish(EXCHANGE_NAME, type, null, msg.getBytes());
}
channel.close();
connection.close();
}
}
四、消费者
package com.example.demo.consume;
import com.example.demo.common.Constant;
import com.example.demo.util.MQConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 路由模式 - 消费者1
*/
public class RouteConsume1 {
private static final String ROUTE_QUEUE_INFO = "route_queue_info";
private static final String EXCHANGE_NAME = "my_exchange_route";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection= MQConnectionUtils.connection();
Channel channel = connection.createChannel();
channel.queueDeclare(ROUTE_QUEUE_INFO, false, false, false, null);
// 1.队列名称 2.交换机名称 3.路由规则
channel.queueBind(ROUTE_QUEUE_INFO, EXCHANGE_NAME, "info");
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String msg = new String(body,"UTF-8");
System.out.println("消费者获取生产者消息:<" + msg +">");
}
};
channel.basicConsume(ROUTE_QUEUE_INFO,true, consumer);
}
}
package com.example.demo.consume;
import com.example.demo.common.Constant;
import com.example.demo.util.MQConnectionUtils;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 路由模式 - 消费者2
*
*/
public class RouteConsume1 {
private static final String ROUTE_QUEUE_ERROR = "route_queue_error";
private static final String EXCHANGE_NAME = "my_exchange_route";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection= MQConnectionUtils.connection();
Channel channel = connection.createChannel();
channel.queueDeclare(ROUTE_QUEUE_ERROR, false, false, false, null);
// 1.队列名称 2.交换机名称 3.路由规则
channel.queueBind(ROUTE_QUEUE_ERROR, EXCHANGE_NAME, "error");
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String msg = new String(body,"UTF-8");
System.out.println("消费者获取生产者消息:<" + msg +">");
}
};
channel.basicConsume(ROUTE_QUEUE_ERROR,true, consumer);
}
}
五、启动服务