一、Direct模型
Direct模型又称订阅/路由发布模型,根据不同的路由规则,不同的消费者通过通道绑定一个到多个路由临时队列,而这些路由队列会监听从交换机发送过来的,指定路由的消息。实现通过路由使区别的广播给不同的消费者。
如下图所示,通过不同的路由设置,消费者1,2,3都会消费来着route_1的消息,消费者2,3会收到来着route_2的消息,消费者3会收到来着route_3的消息
代码实现关键
1. 生产者
//绑定交换机以及申明交换机类型
channel.exchangeDeclare("log_direct", "direct");
通过通道绑定交换机和声明交换机类型, 该交换机不存在时会自动生成。
//通过通道向交换机发送消息,指定交换机, 路由(String), 其他参数,消息本体
channel.basicPublish("log_direct", Route.DIRECT_INFO, null, "Info msg".getBytes());
2. 消费者
//绑定交换机,声明交换机类型
channel.exchangeDeclare("log_direct", "direct");
//生成临时队列并获得名称
String queue = channel.queueDeclare().getQueue();
//绑定队列交换机,声明路由
channel.queueBind(queue,"log_direct",Route.DIRECT_INFO,null);
与生产者一样,先绑定交换机。之后,使用临时队列获取交换机中的消息。
queueBind()
方法通过声明队列,交换机和路由来确定该通道传输怎样路由规则的消息。可以多次使用queueBind()
方法绑定不同的路由规则。
三、代码实现
模拟日志系统, 生产者将发送三种消息:info warning error, 然后通过direct交换机广播给三种消费者。InfoCustomer、WarningCustomer、ErrorCustemor。其中Info只能接受info消息,Warning能接受info、warning消息,Error能接受info、warning、error消息。
1.静态路由提供类
public class Route {
public static final String DIRECT_INFO = "info";
public static final String DIRECT_WARNING = "warning";
public static final String DIRECT_ERROR = "error";
}
2.生产者
public class Provider extends Thread{
@Override
public void run() {
Connection connection = null;
Channel channel = null;
try {
connection = RabbitMqUtil.getConnection();
channel = connection.createChannel();
//绑定交换机, 指定交换机类型
channel.exchangeDeclare("log_direct", "direct");
//发送三条路由为"info" "warning" "error" 的消息到交换器机
channel.basicPublish("log_direct", Route.DIRECT_INFO, null, "Info msg".getBytes());
channel.basicPublish("log_direct", Route.DIRECT_WARNING, null, "Warning msg".getBytes());
channel.basicPublish("log_direct", Route.DIRECT_ERROR, null, "Error msg".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
RabbitMqUtil.closeChannelAndConnection(channel,connection);
}
}
}
3.InfoCustomer
public class InfoCustomer extends Thread{
@Override
public void run() {
Connection connection = null;
Channel channel = null;
try {
connection = RabbitMqUtil.getConnection();
channel = connection.createChannel();
//声明交换机与交换机类型
channel.exchangeDeclare("log_direct", "direct");
//生成临时队列并获得名称
String queue = channel.queueDeclare().getQueue();
//绑定队列交换机,声明路由
channel.queueBind(queue,"log_direct",Route.DIRECT_INFO,null);
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("InfoCustomer 消费了 " + new String(body));
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.WarningCustomer
public class WarningCustomer extends Thread {
@Override
public void run() {
Connection connection = null;
Channel channel = null;
try {
connection = RabbitMqUtil.getConnection();
channel = connection.createChannel();
//声明交换机与交换机类型
channel.exchangeDeclare("log_direct", "direct");
//生成临时队列并获得名称
String queue = channel.queueDeclare().getQueue();
//绑定队列交换机,声明路由
channel.queueBind(queue,"log_direct",Route.DIRECT_INFO,null);
channel.queueBind(queue,"log_direct",Route.DIRECT_WARNING,null);
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("WarningCustomer 消费了 " + new String(body));
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.ErrorCustomer
public class ErrorCustomer extends Thread{
@Override
public void run() {
Connection connection = null;
Channel channel = null;
try {
connection = RabbitMqUtil.getConnection();
channel = connection.createChannel();
//声明交换机与交换机类型
channel.exchangeDeclare("log_direct", "direct");
//生成临时队列并获得名称
String queue = channel.queueDeclare().getQueue();
//绑定队列交换机,声明路由
channel.queueBind(queue,"log_direct",Route.DIRECT_INFO,null);
channel.queueBind(queue,"log_direct",Route.DIRECT_WARNING,null);
channel.queueBind(queue,"log_direct",Route.DIRECT_ERROR,null);
channel.basicConsume(queue,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("ErrorCustomer 消费了 " + new String(body));
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
6.启动方法
public static void main(String[] args) throws InterruptedException {
//仍然需要注意, 消费者因先于生产者被创建
Thread err = new ErrorCustomer();
Thread war = new WarningCustomer();
Thread inf = new InfoCustomer();
err.start();
war.start();
inf.start();
Thread.sleep(1000);
Thread pro = new Provider();
pro.start();
}