RabbitMQ交换机-topic
topic交换机
上次说了direct类型的交换机,这次就说说topic类型的交换机。Direct交换机要求的是绑定键完全匹配后,交换机才会把消息放到队列中,那这样如果我们需要往同一个队列绑定好几个绑定键的时候,就需要绑定好多次了,这样明显不方便。这个时候topic交换机就体现了他的灵活性,可以模糊匹配。绑定的格式还是和之前一样
//将队列绑定到交换机上
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME,"");
下面介绍下模糊匹配的一些特殊字符:
· *(星)可以替代一个单词。
· #(哈希)可以替换零个或多个单词。
我们下面举个例子
从图片上我们可以看出我们使用的是topic交换机,绑定键有三个,队列有两个,其中“*.orange.*”绑定键指向的是Q1队列,“*.*.rabbit”和“lazy.#”绑定键指向的是Q2队列。
将路由密钥设置为“ quick.orange.rabbit ”的消息将传递给两个队列, “ lazy.orange.elephant ”也会去两个队列。另一方面,“ quick.orange.fox ”只会转到第一个队列,而“ lazy.brown.fox ”只能到第二个队列。“ lazy.pink.rabbit ”比较特殊,即使匹配两个绑定键,但是两个绑定键指向同一个队列,所以这个路由秘钥只转发一次并且传递给同Q2。“ quick.brown.fox ”不匹配任何绑定,因此它将被丢弃。
如果我们违反绑定键规则,送一个或四个字的消息,如“orange”或“ quick.orange.male.rabbit ”,会发生什么?那么这些消息将不会匹配任何绑定,并将丢失。
另一方面,“ lazy.orange.male.rabbit ”即使它有四个字,将匹配最后的绑定,并将被传递到第二个队列。
下面是代码的具体实现
生产者
package MQ.Exchange.Topic;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @Title: MQ.WorkQueues.NewTask.java
* @Package MQ.WorkQueues
* @Description: TODO(MQ消息发送到topic的交换机上)
* @Copyright: Copyright (c) 2017 YUANH All Rights Reserved
* @author yuanh
* @date 2017-5-10 下午3:50:35
*/
public classNewTask {
private final static String EXCHANGE_NAME= "topic_logs";
private final static String QUEUE_NAME = "hello_topic";
private final static String QUEUE_NAME2 = "hello_topic1";
private final static String[] topicStr = new String[] { "*.orange.*"};
private final static String[] topicStr2 = new String[] { "*.*.rabbit","lazy.#"};
public static void main(String[] args) throws IOException,TimeoutException {
// 创建连接连接到MabbitMQ
ConnectionFactoryfactory = newConnectionFactory();
// 设置MabbitMQ所在主机ip或者主机名
factory.setHost("127.0.0.1");
factory.setUsername("yuanh");
factory.setPassword("yuanh");
factory.setPort(5672);
factory.setVirtualHost("y_yuanh");
Connectionconnection = factory.newConnection();
// 创建一个频道
Channelchannel = connection.createChannel();
// 声明队列、设置队列持久化
boolean durable = true;
channel.queueDeclare(QUEUE_NAME, durable, false, false, null);
channel.queueDeclare(QUEUE_NAME2, durable, false, false, null);
// 声明fanout交换机、设置持久化
boolean durable2 = true;
channel.exchangeDeclare(EXCHANGE_NAME,"topic",durable2);
// 将队列绑定到交换机上
for (String severity : topicStr) {
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME,severity);
}
for (String severity : topicStr2) {
channel.queueBind(QUEUE_NAME2, EXCHANGE_NAME,severity);
}
Stringmessage = "quick.orange.rabbit";
Stringmessage2 = "lazy.orange.elephant";
Stringmessage3 = "lazy.pink.rabbit";
Stringmessage4 = "quick.brown.fox";
// 将消息放到队列里面
// channel.basicPublish("", QUEUE_NAME, null,message.getBytes());
// 将消息放到交换机上
channel.basicPublish(EXCHANGE_NAME,message, null, message.getBytes());
channel.basicPublish(EXCHANGE_NAME,message2, null,message2.getBytes());
channel.basicPublish(EXCHANGE_NAME,message3, null,message3.getBytes());
channel.basicPublish(EXCHANGE_NAME,message4, null,message4.getBytes());
System.out.println(" 发送 '" + message + "'");
System.out.println(" 发送 '" + message2 + "'");
System.out.println(" 发送 '" + message3 + "'");
System.out.println(" 发送 '" + message4 + "'");
// 关闭通道和连接
channel.close();
connection.close();
}
}
消费者
消费者和之前的一样,只不过是将对列名称改成你需要取的对列名称
package MQ.Exchange.Topic;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
@SuppressWarnings("deprecation")
/**
* @Title: MQ.WorkQueues.Worker.java
* @Package MQ.WorkQueues
* @Description: TODO(MQ消息发送到topic的交换机上)
* @Copyright: Copyright (c) 2017 YUANH All Rights Reserved
* @author yuanh
* @date 2017-5-10 下午3:48:59
*/
public classWorkerResponse {
// private final static String EXCHANGE_NAME ="topic_logs";
private final static String QUEUE_NAME = "hello_topic1";
// private final static String QUEUE_NAME2 ="hello_topic1";
public static void main(String[] argv) throws Exception {
// 创建连接连接到MabbitMQ
ConnectionFactoryfactory = newConnectionFactory();
// 设置MabbitMQ所在主机ip或者主机名
factory.setHost("127.0.0.1");
factory.setUsername("yuanh");
factory.setPassword("yuanh");
factory.setPort(5672);
factory.setVirtualHost("y_yuanh");
Connectionconnection = factory.newConnection();
Channelchannel = connection.createChannel();
// 1声明队列、设置队列持久化
boolean durable = true;
channel.queueDeclare(QUEUE_NAME, durable, false, false, null);
QueueingConsumerconsumer = newQueueingConsumer(channel);
// 2消费者指定消费队列,打开应答机制, 注意false才是打开手动应对,true为自动应答
boolean ack = false;
channel.basicConsume(QUEUE_NAME, ack, consumer);
// 3消费者设置最大服务转发消息数量, 公平转发
int prefetchCount = 1;
channel.basicQos(prefetchCount);
try {
while (true) {
QueueingConsumer.Deliverydelivery = consumer.nextDelivery();
Stringmessage = newString(delivery.getBody());
System.out.println(" 接收 '" + message + "'");
try {
doWork(message);
}finally{
System.out.println("结束");
// 另外需要在每次处理完成一个消息后,手动发送一次应答(ack=false)。
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),
false);
}
}
}catch(Exception e) {
channel.close();
connection.close();
}
}
private static void doWork(String task) throws InterruptedException {
for (char ch : task.toCharArray()){
if (ch == '.') {
Thread.sleep(100);
}else{
Thread.sleep(100);
}
}
}
}