在上一篇博客中,我们实现了工作队列,并且我们的工作队列中的一个任务只会发给一个工作者,除非某个工作者未完成任务意外被杀死,会转发给另外的工作者。 在这篇博客中,我们将实现将一个消息发给多个消费者,这种模式称之为广播。
本质上来说,就是发布的消息会转发给所有的接收者。
交换机(Exchanges)
前面的博客中我们都是通过生产者发送消息给队列,接收者从队列中接收消息。 接下来我们将引入Exchanges。
生产者只能将消息发送给Exchanges。 Exchanges一边从生产者接收消息,另一边将消息推送到队列中。我们可以通过定义转发器的类型进行定义它处理消息的方式。 可用的交换机的类型如下:
- Direct
- Topic
- headers
- fanout
目前我们只关注fanout。 fanout类型交换机特别简单,把所有它接收到的消息,广播到它所绑定的队列中。
在广播模式下,消息发送流程是这样的:
- 可以有多个消费者
- 每个消费者有自己的queue(队列)
- 每个队列都要绑定到Exchange(交换机)
- 生产者发送的消息,只能发送到交换机,交换机来决定要发送给哪个队列,生产者无法决定。
- 交换机把消息发送给绑定过的所有队列
- 队列的消费者都能拿到消息。实现一条消息被多个消费者消费。
代码实现
1.生产者:
public class Provider {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//将通道声明指定交换机
//参数1:交换机名称 参数2:交换机的类型 fanout 广播类型
//没有交换机会创建一共名为logs的交换机
channel.exchangeDeclare("logs","fanout");
//发送消息
channel.basicPublish("logs","",null,"fanout type message".getBytes());
//关闭连接和通道
RabbitMQUtils.closeChannelAndConnection(channel,connection);
}
}
2.消费者1
public class Customer1 {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("logs","fanout");
//创建一个临时的、唯一的队列
//返回的是 临时队列名
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
//参数1: 队列名称 参数2:交换机名称 参数3:路由名称
channel.queueBind(queueName,"logs","");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1:"+new String(body));
}
});
}
}
3.消费者2
public class Customer2 {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("logs","fanout");
//创建一个临时的、唯一的队列
//返回的是 临时队列名
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
//参数1: 队列名称 参数2:交换机名称 参数3:路由名称
channel.queueBind(queueName,"logs","");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2:"+new String(body));
}
});
}
}
4.消费者3
public class Customer3 {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("logs","fanout");
//创建一个临时的、唯一的队列
//返回的是 临时队列名
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
//参数1: 队列名称 参数2:交换机名称 参数3:路由名称
channel.queueBind(queueName,"logs","");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者3:"+new String(body));
}
});
}
}
先运行3个消费者,在运行生产者,可以发送3个消费者都接收到了生产者发送的消息。