发布与订阅
在上一个教程中,我们创建一个工作队列,我们将每个人物,最终恰好分配到一个工人。然而,在这个部分,我们希望每个消息能分配给多个消费者。这种叫发布订阅模式。举例,注册时需要同时发送短信和发送email,我们会将用户注册的信息发给两个消费者,一个专门发送短信消费者,一个专门发送email消费者。
RabbitMQ消息传递模型的核心思想是,生产者不直接想消息队列发送信息。实际上,生产者并不知道消息是否会被传递到任何队列上。
交换机
这里就讲到一个新型概念,交换机(exchange),一方面接收生产者的信息,一方面推送给队列。交换器必须确切地知道如何处理它接收到的消息。它应该被附加到一个特定的队列吗?它应该被添加到许多队列中吗?或者它应该被丢弃。这些规则由exchange类型定义。有几种可用的交换类型:direct、topic、headers和fanout。下面讲:fanout,是一个比较简单的类型。只是将消息广播到它知道的所有队列中去。下图中X就是交换机。
生产者
public class Send {
private final static String EXCHANGE_NAME = "test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection() ;
Channel channel = connection.createChannel();
// 声明队列
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);//分发类型fanout
String msg = "hello world ps";
// 发送信息
channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes());
System.out.println("send success");
// 关闭流
channel.close();
connection.close();
}
}
消费者
public class Rece1 {
private final static String QUEUE_NAME = "test_queu_email";
private final static String EXCHANGE_NAME = "test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 绑定队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 绑定队列到交换机上
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
//qos=1
channel.basicQos(1);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("send email " + new String(body, Charset.defaultCharset()));
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
}
}
public class Rece2 {
private final static String QUEUE_NAME = "test_queu_msg";
private final static String EXCHANGE_NAME = "test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 绑定队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 绑定队列到交换机上
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
//qos=1
channel.basicQos(1);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("send msg " + new String(body, Charset.defaultCharset()));
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);
}
}
官方推荐的queue_name
官方希望能够实现,生成唯一名称queue_name,并且一旦断开生产者连接,队列自动删除。
String queueName = channel.queueDeclare().getQueue();