其实如果直接将消息发送到对列中不仅开销较大,而且耦合度也很大,通常我们都是将生产者将消息发送到Exchange(交换器,下图中的X),再通过Binding将Exchange与Queue关联起来。
在绑定(Binding)Exchange与Queue的同时,一般会指定一个binding key。在绑定多个Queue到同一个Exchange的时候,这些Binding允许使用相同的binding key。
生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里。
RabbitMQ常用的Exchange Type有三种:fanout、direct、topic。
fanout:把所有发送到该Exchange的消息投递到所有与它绑定的队列中。
direct:把消息投递到那些binding key与routing key完全匹配的队列中。
topic:将消息路由到binding key与routing key模式匹配的队列中
我们先实现最基础的fanout模式的一个普通交换机队列
生产者:
package com.hc.exchange;
import com.hc.mqutil.MqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Product {
private final static String EXCHANGE_NAME="exchange_fanout";
public static void main(String[] args) throws Exception {
Connection connection=MqUtil.getConnection();
Channel channel=connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
for(int i=0;i<50;i++){
String message="我是第"+i+"条消息";
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
System.out.println(message);
Thread.sleep(i*10);
}
channel.close();
connection.close();
}
}
消费者1
package com.hc.exchange;
import com.hc.mqutil.MqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
public class Consumer1 {
private final static String QUEUE_NAME="queuetest";
private final static String EXCHANGE_NAME="exchange_fanout";
public static void main(String[] args) throws Exception {
Connection connection=MqUtil.getConnection();
Channel channel=connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//绑定到交换机
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
channel.basicQos(1);
//声明消费者
QueueingConsumer consumer=new QueueingConsumer(channel);
//监听队列,手动返回
channel.basicConsume(QUEUE_NAME, false, consumer);
while(true){
QueueingConsumer.Delivery delivery=consumer.nextDelivery();
String message=new String(delivery.getBody());
System.out.println(message);
Thread.sleep(10);
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
}
消费者2
package com.hc.exchange;
import java.io.IOException;
import cn.itcast.rabbitmq.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
public class Consumer2 {
private final static String QUEUE_NAME="queuetest";
private final static String EXCHANGE_NAME="exchange_fanout";
public static void main(String[] args) throws Exception {
// 获取到连接以及mq通道
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
// 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 绑定队列到交换机
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
// 同一时刻服务器只会发一条消息给消费者
channel.basicQos(1);
// 定义队列的消费者
QueueingConsumer consumer = new QueueingConsumer(channel);
// 监听队列,手动返回完成
channel.basicConsume(QUEUE_NAME, false, consumer);
// 获取消息
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" 搜索系统: '" + message + "'");
Thread.sleep(10);
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
}