RabbitMQ官网提供了七种队列模型,分别是:简单队列、工作队列、发布订阅、路由模式、主题模式、RPC模式、发布者确认模式。
本文在SpringBoot+RabbitMQ环境实现"订阅模式"。
特点:
1、X代表交换机,生产者没有将消息直接发送到队列,而是先发送到了交换机。
2、订阅模式的交换机类型为fanout。
3、一个队列可以有多个消费者,但发送到队列的消息只能被其中一个消费。
订阅模式、路由模式、主题模式,它们三者的队列结构是一模一样的,区别就在于"交换机类型的不同",交换机的类型决定了工作模式的特点。订阅模式的交换机类型是fanout,路由模式的交换机类型是direct,主题模式的交换机类型是topic,所以学习RabbitMQ的各种工作模式,掌握各类型交换机的工作特点很重要。而fanout 交换机的特点就是跟广播一样,对消息不作选择地分发给所有绑定的队列。
下面我们就在SpringBoot中实现一个如上图所示的订阅模式,新建2个项目,一个 rabbitmq-provider (生产者),一个rabbitmq-consumer(消费者)。
> 两个项目的pom依赖和yml配置
org.springframework.boot
spring-boot-starter-amqp
2.2.4.RELEASE
spring:
rabbitmq:
host: xxx.xxx.xx.xxx
port: 5672
virtual-host: felix-vHost
username: long.yuan
password: long.yuan
> 创建两个队列、一个Fanout类型的交换机,将两个队列绑定在交换机上
@Configuration
public class RabbitConfig {
/**
* @Title 创建2个队列
* @Description 创建2个队列
* @Author long.yuan
* @Date 2020/2/29 13:12
* @Param []
* @return org.springframework.amqp.core.Queue
**/
@Bean
public Queue felixQueueA(){
return new Queue("felix-queue-A");
}
@Bean
public Queue felixQueueB() {
return new Queue("felix-queue-B");
}
/**
* @Title 声明一个Fanout类型的交换机
* @Description Fanout类型的交换机会将消息分发到所有的绑定队列,没有RoutingKey的概念
* @Author long.yuan
* @Date 2020/2/29 13:13
* @Param []
* @return org.springframework.amqp.core.FanoutExchange
**/
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("felix-fanout-exchange");
}
/**
* @Title 将上面创建的2个队列绑定到交换机
* @Description 将上面创建的2个队列绑定到交换机
* @Author long.yuan
* @Date 2020/2/29 13:15
* @Param [aMessage, fanoutExchange]
* @return Binding
**/
@Bean
Binding bindingExchangeA(Queue felixQueueA, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(felixQueueA).to(fanoutExchange);
}
@Bean
Binding bindingExchangeB(Queue felixQueueB, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(felixQueueB).to(fanoutExchange);
}
}
> 生产者将消息发到交换机上
@Component
public class Publisher {
@Autowired
private AmqpTemplate rabbitTemplate;
/**
* @Title 生产者将消息发送到交换机
* @Description 生产者将消息发送到交换机
* @Author long.yuan
* @Date 2020/2/29 13:29
* @Param [i]
* @return void
**/
public void sendMessage() {
String message = "发布订阅模式-message";
System.out.println("发送消息 : " + message);
rabbitTemplate.convertAndSend("felix-fanout-exchange","",message);
}
}
> 创建3个消费者,一个消费者监控队列A,其余两个消费者监控队列B
@Component
public class Consumer {
@RabbitListener(queues = "felix-queue-A")
@RabbitHandler
public void processA(String message) {
System.out.println("customerA消费queueA消息成功: " + message);
}
@RabbitListener(queues = "felix-queue-B")
@RabbitHandler
public void processB1(String message) {
System.out.println("customerB1消费queueB消息成功: " + message);
}
@RabbitListener(queues = "felix-queue-B")
@RabbitHandler
public void processB2(String message) {
System.out.println("customerB2消费queueB消息成功: " + message);
}
}
运行test方法发送消息,启动消费者,看结果
可以看到,消息被同时发送到了A、B两个队列,B队列有两个消费者,但只有其中一个消费者B1消费了消息。
订阅模式的交换机类型是Fanout,Fanout交换机的特点,就决定了订阅模式的工作模式,即消息先发送到交换机,交换机对消息不作选择地分发给所有绑定的队列。
感兴趣的小伙伴可以关注一下博主的公众号,1W+技术人的选择,致力于原创技术干货,包含Redis、RabbitMQ、Kafka、SpringBoot、SpringCloud、ELK等热门技术的学习&资料。