1.概述
1.1 消费者绑定
在前面的示例中,我们已经在创建绑定。您可能会想起以下代码:
channel.queueBind(queueName,EXCHANGE_NAME,"");
绑定是交换和队列之间的关系。可以简单地理解为:队列对来自此交换的消息感兴趣。
绑定可以使用额外的routingKey参数。为了避免与basic_publish参数混淆,我们将其称为绑定键。这是我们如何使用键创建绑定的方法:
channel.queueBind(queueName,EXCHANGE_NAME,"key1");
1.2 直接交换 - direct
直接交换背后的路由算法很简单-一条消息进入其绑定密钥与该消息的路由密钥完全匹配的队列 。
为了说明这一点,请考虑以下设置:
在此设置中,我们可以看到绑定了两个队列的直接交换X。第一个队列由绑定键orange绑定,第二个队列有两个绑定,一个绑定键为black,另一个绑定为green。
在这样的设置中,使用路由键orange发布到交换机的消息 将被路由到队列Q1。路由键为black 或green 的消息将转到Q2。所有其他消息将被丢弃。
1.3 多重绑定
用相同的绑定密钥绑定多个队列是完全合法的。在我们的示例中,我们可以使用绑定键black在X和Q1之间,X和Q2之间添加绑定。在这种情况下,直接交换的行为将类似于扇出,并将消息广播到所有匹配的队列。带有黑色路由键的消息将同时传递到 Q1和Q2
2.代码示例
2.1 发送者
public class RouteSender {
private final static String EXCHANGE_NAME = "testRoute";//交换机名称
public static void main(String[] args) throws Exception {
//1.获取连接
Connection connection = ConnectionUtil.getConnection();
//2.创建通道
Channel channel = connection.createChannel();
//3.1 声名交换机
//参数1,交换机名称
//参数2,交换机类型,默认 direct(直接)
channel.exchangeDeclare(EXCHANGE_NAME,"direct");
//4.发送消息
String msg = "发送路由消息";
channel.basicPublish(EXCHANGE_NAME,"key3",null,msg.getBytes());
//5.关闭连接
channel.close();
connection.close();
}
2.2 消费者1
public class RouteRecv1 {
private final static String EXCHANGE_NAME = "testRoute";//交换机名称
private final static String QUEUE1 = "testQueue1";//临时队列名称
public static void main(String[] args) throws Exception {
//1.获取连接
Connection connection = ConnectionUtil.getConnection();
//2.创建通道
Channel channel = connection.createChannel();
//3.1 临时队列
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String queueName = channel.queueDeclare().getQueue();
//3.2 绑定队列到交换机
//queue
//exchange
//routingKey 绑定键,绑定到交互及的时候会指定一个标记,只有和它一样的标记的消息才会被当前消费者接收到
channel.queueBind(queueName,EXCHANGE_NAME,"key1");
//如果要接收多个标记,只需要再执行一次即可
channel.queueBind(queueName,EXCHANGE_NAME,"key2");
//4.公平派遣:通知服务器,在消费确认前,不接收新发送的消息
channel.basicQos(1);
//5.定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//打印收到的消息
System.out.println("消费者11收到内容:"+new String(body));
//7.消费者消息确认:参数2,false 为手动确认收到消息。
//这里可以在异常捕获的时候,将它设置为true
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
//6.注册消费者,参数2,false代表我们收到消息后需要手动告诉服务器
channel.basicConsume(queueName,false,consumer);
}
}
2.3 消费者2
public class RouteRecv2 {
private final static String EXCHANGE_NAME = "testRoute";//交换机名称
private final static String QUEUE1 = "testQueue1";//临时队列名称
public static void main(String[] args) throws Exception {
//1.获取连接
Connection connection = ConnectionUtil.getConnection();
//2.创建通道
Channel channel = connection.createChannel();
//3.1 临时队列
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String queueName = channel.queueDeclare().getQueue();
//3.2 绑定队列到交换机
//queue
//exchange
//routingKey 绑定键,绑定到交互及的时候会指定一个标记,只有和它一样的标记的消息才会被当前消费者接收到
channel.queueBind(queueName,EXCHANGE_NAME,"key1");
//如果要接收多个标记,只需要再执行一次即可
channel.queueBind(queueName,EXCHANGE_NAME,"key3");
//4.公平派遣:通知服务器,在消费确认前,不接收新发送的消息
channel.basicQos(1);
//5.定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//打印收到的消息
System.out.println("消费者22收到内容:"+new String(body));
//7.消费者消息确认:参数2,false 为手动确认收到消息。
//这里可以在异常捕获的时候,将它设置为true
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
//6.注册消费者,参数2,false代表我们收到消息后需要手动告诉服务器
channel.basicConsume(queueName,false,consumer);
}
}
RouteSender.java中,当参数routingKey为key1,key2,key3时,查看不通的接收结果。
channel.basicPublish(EXCHANGE_NAME,"key3",null,msg.getBytes());