目录
简述
交换机模式
Fanout模式
Direct模式
Topic模式
Headers模式
生产者不直接跟队列打交道,而是通过交换机。交换机类似于生产者和队列直接的一个管理者,它将生产的消息分配给对应的队列。
前期准备pom.xml中的依赖
org.springframework.boot
spring-boot-starter-amqp
具体整合详细可见 整合Springboot和RabbitMQ
又叫广播模式,类似于一个微信公众号,当公众号发布消息的时候所有关注该公众号的用户都能收到消息,FanoutExchange的功能就类似与公众号。
测试步骤
Config中配置两个队列分别为03和04在配置一个FanoutExchange交换机
将交换机和两个队列03,04分别绑定
发送消息给交换机
分别接收03和04队列的消息
配置Config
package com.shao.seckill.config;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfigFanout {
//准备两个队列名称和一个交换机名称
private static final String QUEUE03 = "queue_fanout01";
private static final String QUEUE04 = "queue_fanout02";
private static final String EXCHANGE02 = "fanoutExchange";
//创建队列QUEUE01
@Bean
public Queue queue01(){
return new Queue(QUEUE03);
}
//创建队列QUEUE02
@Bean
public Queue queue02(){
return new Queue(QUEUE04);
}
//创建交换机EXCHANGE
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange(EXCHANGE02);
}
//将EXCHANGE和QUEUE01绑定
@Bean
public Binding binding01(){
return BindingBuilder.bind(queue01()).to(fanoutExchange());
}
//将EXCHANGE和QUEUE02绑定
@Bean
public Binding binding02(){
return BindingBuilder.bind(queue02()).to(fanoutExchange());
}
}
生产者/发送者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQSender {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息给fanoutExchange
* @param msg
*/
public void sendtoFanoutExchange(Object msg){
log.info("发送消息:"+msg);
rabbitTemplate.convertAndSend("fanoutExchange","",msg);
}
}
消费者/接收者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQReceiver {
//从queue_fanout01队列中接收消息
@RabbitListener(queues = "queue_fanout01")
public void receiver01(Object msg){
log.info("QUEUE01接收消息:"+msg);
}
//从queue_fanout02队列中接收消息
@RabbitListener(queues = "queue_fanout02")
public void receiver02(Object msg){
log.info("QUEUE02接收消息:"+msg);
}
}
控制台打印结果
MQSender : 发送消息:Hello
MQReceiver : QUEUE01接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=fanoutExchange, receivedRoutingKey=, deliveryTag=1, consumerTag=amq.ctag-UIsBEjz13DiHyE60FUbZnw, consumerQueue=queue_fanout01])
MQReceiver : QUEUE02接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=fanoutExchange, receivedRoutingKey=, deliveryTag=1, consumerTag=amq.ctag-C5iC4RWpyAkD7PaoGU3eEg, consumerQueue=queue_fanout02])
Fanout模式原理图
p:生产者 X:交换机
RabbitMQ交换机绑定关系
直接模式,该模式主要是利用路由键(routing key),交换机通过该键连接对应的队列将信息放入对应的队列中
测试步骤
Config中配置两个队列分别为01和02在配置一个DirectExchange交换机
将交换机和队列01以及路由键red绑定,将交换机和队列02以及路由键green和red绑定
发送消息给交换机对应的路由键
绑定该键的队列接收消息
配置config
package com.shao.seckill.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfigDirect {
private static final String QUEUE01 = "queue_direct01";
private static final String QUEUE02 = "queue_direct02";
private static final String EXCHANGE = "directExchange";
private static final String ROUTINGKEY01 = "queue.red";
private static final String ROUTINGKEY02 = "queue.green";
@Bean
public Queue queue03(){
return new Queue(QUEUE01);
}
@Bean
public Queue queue04(){
return new Queue(QUEUE02);
}
@Bean
public DirectExchange directExchange(){
return new DirectExchange(EXCHANGE);
}
@Bean
public Binding binding03(){
return BindingBuilder.bind(queue03()).to(directExchange()).with(ROUTINGKEY01);
}
@Bean
public Binding binding04(){
return BindingBuilder.bind(queue04()).to(directExchange()).with(ROUTINGKEY02);
}
@Bean
public Binding binding05(){
return BindingBuilder.bind(queue04()).to(directExchange()).with(ROUTINGKEY01);
}
}
生产者/发送者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQSender {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息给sendtoDirectExchange的routingkey为red的队列
* @param msg
*/
public void sendtoDirectExchanger(Object msg){
log.info("发送red消息:"+msg);
rabbitTemplate.convertAndSend("directExchange","queue.red",msg);
}
/**
* 发送消息给sendtoDirectExchange的routingkey为green的队列
* @param msg
*/
public void sendtoDirectExchangeg(Object msg){
log.info("发送green消息:"+msg);
rabbitTemplate.convertAndSend("directExchange","queue.green",msg);
}
}
消费者/接收者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQReceiver {
@RabbitListener(queues = "queue_direct01")
public void receiver03(Object msg){
log.info("QUEUE03接收消息:"+msg);
}
@RabbitListener(queues = "queue_direct02")
public void receiver04(Object msg){
log.info("QUEUE04接收消息:"+msg);
}
}
控制台打印结果
QUEUE03与QUEUE04都绑定red路由键
QUEUE04只绑定green路由键
MQSender : 发送red消息:Hello
MQReceiver : QUEUE03接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=directExchange, receivedRoutingKey=queue.red, deliveryTag=1, consumerTag=amq.ctag-wi7Cxn2luvzWqd-nDnzNQw, consumerQueue=queue_direct01])
MQReceiver : QUEUE04接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=directExchange, receivedRoutingKey=queue.red, deliveryTag=1, consumerTag=amq.ctag-ZaSyHHzV9FwQUlRcUGTYmA, consumerQueue=queue_direct02])
MQSender : 发送green消息:Hello
MQReceiver : QUEUE04接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=directExchange, receivedRoutingKey=queue.green, deliveryTag=1, consumerTag=amq.ctag-k9UmEuRrmNlbJpWAviBGRg, consumerQueue=queue_direct02])
Direct模式原理图
RabbitMQ绑定关系
类似于direct模式,属于direct模式的扩展,允许routing key使用* 和 # 作为通配符
*表示匹配精确的一个
#表示匹配零个或多个
例如
①#.queue.# ②*.queue.#
ask.abc.queue.ccd.aac 被①匹配不被②
abc.queue.acc 被①②匹配
测试步骤
Config中配置两个队列分别为05和06再配置一个TopicExchange交换机
将交换机和队列05以及路由键#.queue.#绑定,将交换机和队列06以及路由键*.queue.#绑定
发送第一则消息给交换机对应的路由键是ask.abc.queue.ccd.aac;
发送第二则消息给交换机对应的路由键是abc.queue.acc;
收到第一则消息:队列05
收到第二则消息:队列05,队列06
配置config
package com.shao.seckill.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfigTopic {
private static final String QUEUE05 = "queue_topic01";
private static final String QUEUE06 = "queue_topic02";
private static final String EXCHANGE03 = "topicExchange";
private static final String ROUTINGKEY05 = "#.queue.#";
private static final String ROUTINGKEY06 = "*.queue.#";
@Bean
public Queue queue05(){
return new Queue(QUEUE05);
}
@Bean
public Queue queue06(){
return new Queue(QUEUE06);
}
@Bean
public TopicExchange topicExchange(){
return new TopicExchange(EXCHANGE03);
}
@Bean
public Binding binding06(){
return BindingBuilder.bind(queue05()).to(topicExchange()).with(ROUTINGKEY05);
}
@Bean
public Binding binding07(){
return BindingBuilder.bind(queue06()).to(topicExchange()).with(ROUTINGKEY06);
}
}
生产者/发送者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQSender {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息给sendtoTopicExchange的队列
* @param msg
*/
public void sendtoTopicExchange01(Object msg){
log.info("发送消息(QUEUE05)接收:"+msg);
rabbitTemplate.convertAndSend("topicExchange","ask.abc.queue.ccd.aac",msg);
}
/**
* 发送消息给sendtoTopicExchange的队列
* @param msg
*/
public void sendtoTopicExchange02(Object msg){
log.info("发送消息(QUEUE05,QUEUE06)接收:"+msg);
rabbitTemplate.convertAndSend("topicExchange","abc.queue.acc",msg);
}
}
消费者/接收者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQReceiver {
@RabbitListener(queues = "queue_topic01")
public void receiver05(Object msg){
log.info("QUEUE05接收消息:"+msg);
}
@RabbitListener(queues = "queue_topic02")
public void receiver06(Object msg){
log.info("QUEUE06接收消息:"+msg);
}
}
控制台打印结果
测试结果
MQSender : 发送消息(QUEUE05)接收:Hello
MQReceiver : QUEUE05接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=topicExchange, receivedRoutingKey=ask.abc.queue.ccd.aac, deliveryTag=1, consumerTag=amq.ctag-vkk1y8YfLjnz3KlpAodUYQ, consumerQueue=queue_topic01])
MQSender : 发送消息(QUEUE05,QUEUE06)接收:Hello
MQReceiver : QUEUE06接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=topicExchange, receivedRoutingKey=abc.queue.acc, deliveryTag=1, consumerTag=amq.ctag-5RTgXGDh2oVjJ-GzrL6TgQ, consumerQueue=queue_topic02])
MQReceiver : QUEUE05接收消息:(Body:'Hello' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=topicExchange, receivedRoutingKey=abc.queue.acc, deliveryTag=1, consumerTag=amq.ctag-q_woN3VR6Pim2oPtT4akiA, consumerQueue=queue_topic01])
Topic模式原理图
RabbitMQ绑定关系
该模式不使用routing key而是使用键值对的匹配方式来实现交换机和队列的匹配
该模式效率比routing key的效率低并且实现比较复杂
测试步骤
Config中配置两个队列分别为08和09再配置一个HeaderExchange交换机
Map
map = new HashMap<>(); map.put("color","red"); map.put("speed","low"); 将交换机和队列08绑定并设置whereAny(map)
将交换机和队列09绑定并设置whereAll(map)
MessageProperties properties = new MessageProperties(); properties.setHeader("color","red"); properties.setHeader("speed","low"); Message message =new Message(msg.getBytes(),properties); //发送第一则消息给交换机并设置头信息,此时发送的是Message对象 rabbitTemplate.convertAndSend("headerExchange","",message);
MessageProperties properties = new MessageProperties(); properties.setHeader("color","red"); Message message =new Message(msg.getBytes(),properties); //发送第二则消息给交换机并设置头信息,此时发送的是Message对象 rabbitTemplate.convertAndSend("headerExchange","",message);
收到第一则消息:队列08,队列09
收到第二则消息:队列08
配置config
package com.shao.seckill.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class RabbitMQConfigHeader {
private static final String QUEUE08 = "queue_header01";
private static final String QUEUE09 = "queue_header02";
private static final String EXCHANGE05 = "headerExchange";
@Bean
public Queue queue08(){
return new Queue(QUEUE08);
}
@Bean
public Queue queue09(){
return new Queue(QUEUE09);
}
@Bean
public HeadersExchange headersExchange(){
return new HeadersExchange(EXCHANGE05);
}
//whereAny(map):满足map中的任意一个即可
@Bean
public Binding binding10(){
Map map = new HashMap<>();
map.put("color","red");
map.put("speed","low");
return BindingBuilder.bind(queue08()).to(headersExchange()).whereAny(map).match();
}
//whereAll(map):同时满足map的所有才可以发送
@Bean
public Binding binding11(){
Map map = new HashMap<>();
map.put("color","red");
map.put("speed","low");
return BindingBuilder.bind(queue09()).to(headersExchange()).whereAll(map).match();
}
}
生产者/发送者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQSender {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendtoHeaderExchange01(String msg){
log.info("发送的信息(被两个queue接收):"+msg);
MessageProperties properties = new MessageProperties();
properties.setHeader("color","red");
properties.setHeader("speed","low");
Message message =new Message(msg.getBytes(),properties);
rabbitTemplate.convertAndSend("headerExchange","",message);
}
public void sendtoHeaderExchange02(String msg){
log.info("发送的信息(被QUEUE08接收):"+msg);
MessageProperties properties = new MessageProperties();
properties.setHeader("speed","low");
Message message =new Message(msg.getBytes(),properties);
rabbitTemplate.convertAndSend("headerExchange","",message);
}
}
消费者/接收者
package com.shao.seckill.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MQReceiver {
@RabbitListener(queues = "queue_header01")
public void receiver07(Message message){
log.info("QUEUE08接收消息:"+new String(message.getBody()));
}
@RabbitListener(queues = "queue_header02")
public void receiver08(Message message){
log.info("QUEUE09接收消息:"+new String(message.getBody()));
}
}
控制台打印结果
MQSender : 发送的信息(被两个queue接收):Hello
MQReceiver : QUEUE08接收消息:Hello MQReceiver : QUEUE09接收消息:Hello
MQSender : 发送的信息(被QUEUE08接收):Hello
MQReceiver : QUEUE08接收消息:Hello
RabbitMQ绑定关系