在订阅模型中,多了一个exchange角色,而且过程略有变化:
- Publisher:生产者,也就是要发送消息的程序,但是不再发送到消息队列中,而是发送给交换机
- Exchange:交换机,接收生产者发送的消息,知道如何处理消息,如:递交给某个队列、递交给所有队列、或是将消息丢弃。如何操作,取决于Exchange的类型。
- Exchange有以下3种类型:
- Fanout:广播,将消息发送给所有绑定到交换机的队列。
- Direct:定向,将消息发送给符合指定 routing key 的队列。
- Topic:通配符,将消息发送给符合 routing pattern(路由模式)的队列。
- Consumer:消费者,与以前一样,订阅队列。
- Queue:接收消息、缓存消息。
Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此 如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息就会丢失。
Fanout(广播模式)
Fanout Exchange 会将接收到的消息广播到每一个跟其绑定的queue
Fanout消息发送流程
- 可以有多个队列
- 每个队列都要绑定到Exchange
- 生产者发送的消息,只能发送给交换机,交换机来决定要发给哪个队列。
- 交换机把消息发送给绑定的所有队列。
- 订阅队列的消费者都能拿到消息。
声明交换机与队列
- 创建一个Fanout类型的交换机,名称为 my.fanout
- 创建两个队列:fanout.A、fanout.B
- 将队列绑定到交换机
@Configuration
public class FanoutRabbitConfig {
/**
* 创建交换机
*/
@Bean
public FanoutExchange fanoutExchange() {
//创建名为fanoutExchange的交换机
return new FanoutExchange("my.fanout");
}
/**
* 创建队列fanout.A
*/
@Bean
public Queue AMessage() {
return new Queue("fanout.A");
}
/**
* 创建队列fanout.B
*/
@Bean
public Queue BMessage() {
return new Queue("fanout.B");
}
/**
* 绑定队列 fanout.A 到交换机
*/
@Bean
public Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(AMessage).to(fanoutExchange);
}
/**
* 绑定队列 fanout.B 到交换机
*/
@Bean
public Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(BMessage).to(fanoutExchange);
}
}
消息发送
通过rabbitTemplate.convertAndSend()方法将消息发送给交换机
@Component
public class FanoutSender {
@Resource
private AmqpTemplate rabbitTemplate;
public void send() {
String context = "hello, everyone";
System.out.println("生产者发送消息: " + context);
this.rabbitTemplate.convertAndSend("my.fanout", "", context);
}
}
消息接收
使用@RabbitListener注解分别监听两个队列
@Component
public class FanoutListener {
//分别监听三个队列
@RabbitListener(queues = "fanout.A")
public void listenQueueA(String msg) {
System.out.println("消费者A接收到: " + msg);
}
@RabbitListener(queues = "fanout.B")
public void listenQueueB(String msg) {
System.out.println("消费者B接收到: " + msg);
}
}