上一篇说的RabbitMQ的6种工作模式---简单模式,这篇说一下工作队列模式和交换机模式(也叫订阅模式)
代码基于spring boot + JDK1.8,需要两个两个项目,springbootmqproducers(生产者)、springbootmq(两个消费者)
工作队列模式:
这种模式出现了多个消费者,为了保证消费者之间的负载均衡和同步,需要再消息队列之间加上同步功能。
主要思想:
避免立即执行资源密集型任务(耗时),以便下一个任务执行时不用等待它完成。工作队列将任务封装为消息并将其发送到队列中。
流程图:
代码:
代码在原来的基础上,再添加一个消费者DirectReceiverA,原来代码请查阅这里
package com.lyc.springbootmq.customer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 监听的队列名称 lycDirectQueue
* 第二个消费者
*/
@Component
@RabbitListener(queues = "lycDirectQueue")//监听的队列名称 TestDirectQueue
public class DirectReceiverA {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("第二个消费者收到消息 : " + testMessage.toString());
}
}
然后启动生产者和消费者的两个项目,连续访问localhost:6060/rabbiMQDemo/sendDirectMessage
可以在控制台看到以下输出
说明这两个消费者都消费了。实现了负载均衡
交换机模式:
实际上,在前面两种模式已经使用了交换机,在生产者代码里,有配置交换机名称。
//Direct交换机 起名:LycDirectExchange
@Bean
DirectExchange LycDirectExchange() {
return new DirectExchange("lycDirectExchange",true,false);
}
让我们看一下DirectExchange的参数都有什么
name.:交换机名称;durable:是否持久化,一般填ture;autoDelete:用完是否自动删除
流程图:
如果消息配置的交换机配置的参数和RabbitMQ队列绑定(binding)的交换机名称相同,则转发。否则丢弃。此处交换机类型是fanout(扇形)
这种形式的需要多个队列,多个消费者,消费指定的信息,也就是一个消费者对应一个队列
代码如下:
在生产者新增配置代码,新增扇形交换机
package com.lyc.springbootmqproducers.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 扇形交换机
**/
@Configuration
public class FanoutRabbitConfig {
/**
* 创建三个队列 :fanout.A fanout.B fanout.C
* 将三个队列都绑定在交换机 fanoutExchange 上
* 因为是扇型交换机, 路由键无需配置,配置也不起作用
*/
@Bean
public Queue queueA() {
return new Queue("QueueA");
}
@Bean
public Queue queueB() {
return new Queue("QueueB");
}
@Bean
public Queue queueC() {
return new Queue("QueueC");
}
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");
}
@Bean
Binding bindingExchangeA() {
return BindingBuilder.bind(queueA()).to(fanoutExchange());
}
@Bean
Binding bindingExchangeB() {
return BindingBuilder.bind(queueB()).to(fanoutExchange());
}
@Bean
Binding bindingExchangeC() {
return BindingBuilder.bind(queueC()).to(fanoutExchange());
}
}
新增访问方法
@GetMapping("/sendFanoutMessage1")
public String sendFanoutMessage() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: testFanoutMessage ";
Map<String, Object> map = new HashMap<>();
map.put("messageData", messageData);
rabbitTemplate.convertAndSend("fanoutExchange", null, map);
return "ok";
}
在消费者中新增三个消费者,分别监听三个队列
package com.lyc.springbootmq.customer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 监听的队列名称 QueueC
* 第三个消费者
*/
@Component
@RabbitListener(queues = "QueueC")//监听的队列名称 TestDirectQueue
public class DirectReceiverC {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("第三个消费者收到消息 : " + testMessage.toString());
}
}
package com.lyc.springbootmq.customer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 监听的队列名称 QueueB
* 第一个消费者
*/
@Component
@RabbitListener(queues = "QueueA")//监听的队列名称 TestDirectQueue
public class DirectReceiverA {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("第一个消费者收到消息 : " + testMessage.toString());
}
}
package com.lyc.springbootmq.customer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 监听的队列名称 QueueB
* 第二个消费者
*/
@Component
@RabbitListener(queues = "QueueB")//监听的队列名称 TestDirectQueue
public class DirectReceiverB {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("第二个消费者收到消息 : " + testMessage.toString());
}
}
测试启动生产者,会发现MQ界面中出现三个队列
访问localhost:6060/rabbiMQDemo/sendFanoutMessage1,三个队列都会有一条消息
启动消费者项目会出现以下
说明这三个队列的消息全部被消费
好了,这两个模式说完了,现在小结一下
小结:
1.工作队列模式和交换机模式都是需要多个消费者
2.不同消费者可以监听同一个队列,可以负载均衡
3.不同消费者监听不同队列,可以实现注册后发邮件和发短信的业务
5.不同消费者监听不同队列,当交换机为fanout(广播)模式时,可以实现订阅功能
4.在扇形交换机中,路由键(routing key)失效,配置之后也不能用
下一篇继续说RabbitMQ的其他工作模式