前面学习的fanout模式,我们清楚,这种模式使用起来不太灵活——因为他会将消息分发给所有绑定的队列。所以,有时候会用到另一种交换规则——direct(直连)。直连交换机很简单,就是交换机会将消息路由到消息的路由键(routingKey)与队列的路由键完全匹配的队列中。
概念
过程如下:
其中,队列1 绑定了路由键error,队列2 绑定了info,error,warning路由键。
首先,消息发送到交换机,然后交换机会根据路由键将消息路由到对应得队列上。
代码
绑定error路由键的Recv1.java
package com.xsw.direct;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/*
绑定error路由键
*/
public class Recv1 {
private final static String EXCHANGE_NAME = "directTest";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.56.101");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//声明直连交换机
channel.exchangeDeclare(EXCHANGE_NAME,"direct");
//声明队列
String queueName = channel.queueDeclare().getQueue();
//绑定
channel.queueBind(queueName,EXCHANGE_NAME,"error");
System.out.println("Recv1 waiting message...");
DeliverCallback deliverCallback = (consumerTag,deliver)->{
String message = new String(deliver.getBody(),"UTF-8");
System.out.println("received "+deliver.getEnvelope().getRoutingKey()+":"+message);
};
channel.basicConsume(queueName,true,deliverCallback,consumetTag->{});
}
}
绑定error,info,warning的Recv2.java
package com.xsw.direct;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/*
绑定三个路由键:error,info,warning
*/
public class Recv2 {
private final static String EXCHANGE_NAME = "directTest";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.56.101");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//声明直连交换机
channel.exchangeDeclare(EXCHANGE_NAME,"direct");
//声明队列
String queueName = channel.queueDeclare().getQueue();
//绑定
channel.queueBind(queueName,EXCHANGE_NAME,"error");
channel.queueBind(queueName,EXCHANGE_NAME,"info");
channel.queueBind(queueName,EXCHANGE_NAME,"warning");
System.out.println("Recv2 waiting message...");
DeliverCallback deliverCallback = (consumerTag,deliver)->{
String message = new String(deliver.getBody(),"UTF-8");
System.out.println("received "+deliver.getEnvelope().getRoutingKey()+":"+message);
};
channel.basicConsume(queueName,true,deliverCallback,consumetTag->{});
}
}
启动RabbitMQ服务器,然后在运行Recv1和Recv2,可以看到:
绑定关系:
再运行发送端程序,发送路由键为error的消息
String message = "hello direct";
String routingKey = "error";
可以看到Recv1和Recv2都接收到了消息:
此时再运行发送端程序,发送路由键为warning的信息:
String message = "hello direct";
String routingKey = "warning";
观察Recv1和Recv2,只有Recv2接收到了信息:
完整的Send.java
package com.xsw.direct;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Send {
private final static String EXCHANGE_NAME = "directTest";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.56.101");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//声明直连交换机
channel.exchangeDeclare(EXCHANGE_NAME,"direct");
String message = "hello direct";
// String routingKey = "error";
// String routingKey = "info";
String routingKey = "warning";
channel.basicPublish(EXCHANGE_NAME,routingKey,null,message.getBytes());
System.out.println("send message:"+message);
channel.close();
connection.close();
}
}