RabbitMQ给我们提供了四种Exchange模式,分别为:fanout,direct,topic,header
一:Direct Exchange
与指定交换机绑定的所有队列都可以接收到消息,任何发送到Direct Exchange的消息都会被转发到RouteKey中指定的Queue,如果不存在RouteKey中指定的队列名,则该消息会被抛弃。
案例:比如两人谈恋爱,单独发送消息:
发送消息设置,及接收短信
调用sendDirect方法运行结果如下:
二:Topic Exchange
任何发送到Topic Exchange的消息都会被转发到所有关心RouteKey中指定话题的Queue上,如发送到交换机test.topic的消息routingKey有routing_topic.1、routing_topic.2, 则在绑定消息队列与路由时指定 * routing_topic.*就可以同时匹配这两个routingKey, 就可以接收发送到交换机test.topic, 路由为routing_topic.1、routing_topic.2的消息。
案例:发工资时,员工只接收自己工资信息,经理则同时接收自己薪资和员工薪资:
调用sendTopic方法运行结果如下:
三:Fanout Exchange
即路由模式,与指定交换机绑定的所有队列都可以接收到消息,任何发送到Fanout Exchange的消息都会被转发到与该Exchange绑定(Binding)的所有Queue上。
案例:所有人接收到开会通知:
调用sendFanout方法运行结果如下:
四:Header Exchange
header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配队列
案例:车辆出现违规,则需要根据预留通知消息类型进行通知:
all :表示所有的键值对都匹配才能接受到消息,any :表示只要有键值对匹配就能接受到消息
运行sendHeader方法,效果如下:
所涉及类如下:MqController
package com.controller;/**
* @author :Hj
* @date 2020/7/23
*/
import com.MQSender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/rabbitMq")
public class MqController {
@Autowired
private MQSender helloSender1;
@ResponseBody
@RequestMapping("/direct")
public String direct() {
helloSender1.sendDirect();
return "direct模式";
}
@ResponseBody
@RequestMapping("/topic")
public String topic() {
helloSender1.sendTopic();
return "topic模式";
}
@ResponseBody
@RequestMapping("/fanout")
public String fanout() {
helloSender1.sendFanout();
return "fanout模式";
}
@ResponseBody
@RequestMapping("/header")
public String header() {
helloSender1.sendHeader();
return "header模式";
}
}
MQconfig
package com.rabbitmq;/**
* @author :Hj
* @date 2020/7/23
*/
import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.HeadersExchange;
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 MQConfig {
public static final String TOPIC_QUEUE1 = "topic.queue1";
public static final String TOPIC_QUEUE2 = "topic.queue2";
public static final String HEADER_QUEUE = "header.queue";
public static final String HEADER_QUEUE1= "header.queue1";
public static final String HEADER_QUEUE2 = "header.queue2";
public static final String TOPIC_EXCHANGE = "topicExchage";
public static final String FANOUT_EXCHANGE = "fanoutxchage";
public static final String HEADERS_EXCHANGE = "headersExchage";
public static final String helloQueue = "helloQueue";
/**
* Direct模式 交换机Exchange
* 与指定交换机绑定的所有队列都可以接收到消息
*
*任何发送到Direct Exchange的消息都会被转发到RouteKey中指定的Queue。
1.一般情况可以使用rabbitMQ自带的Exchange:”"(该Exchange的名字为空字符串,下文称其为default Exchange)。
2.这种模式下不需要将Exchange进行任何绑定(binding)操作
3.消息传递时需要一个“RouteKey”,可以简单的理解为要发送到的队列名字。
4.如果vhost中不存在RouteKey中指定的队列名,则该消息会被抛弃。
*
* */
@Bean
public Queue queue() {
return new Queue(helloQueue, true);
}
/**
* Topic模式 交换机Exchange
* 例如发送到交换机test.topic的消息routingKey有routing_topic.1、routing_topic.2, 则在绑定消息队列与路由时指定
* routing_topic.*就可以同时匹配这两个routingKey, 就可以接收发送到交换机test.topic, 路由为routing_topic.1、routing_topic.2的消息。
*
* 任何发送到Topic Exchange的消息都会被转发到所有关心RouteKey中指定话题的Queue上
1.这种模式较为复杂,简单来说,就是每个队列都有其关心的主题,所有的消息都带有一个“标题”(RouteKey),Exchange会将消息转发到所有关注主题能与RouteKey模糊匹配的队列。
2.这种模式需要RouteKey,也许要提前绑定Exchange与Queue。
3.在进行绑定时,要提供一个该队列关心的主题,如“#.log.#”表示该队列关心所有涉及log的消息(一个RouteKey为”MQ.log.error”的消息会被转发到该队列)。
4.“#”表示0个或若干个关键字,“*”表示一个关键字。如“log.*”能与“log.warn”匹配,无法与“log.warn.timeout”匹配;但是“log.#”能与上述两者匹配。
5.同样,如果Exchange没有发现能够与RouteKey匹配的Queue,则会抛弃此消息。
* */
@Bean
public Queue topicQueue1() {
return new Queue(TOPIC_QUEUE1, true);
}
@Bean
public Queue topicQueue2() {
return new Queue(TOPIC_QUEUE2, true);
}
@Bean
public TopicExchange topicExchage(){
return new TopicExchange(TOPIC_EXCHANGE);
}
@Bean
public Binding topicBinding1() {
return BindingBuilder.bind(topicQueue1()).to(topicExchage()).with("topic.key1");//员工张三只接收自己薪资信息
}
@Bean
public Binding topicBinding2() {
return BindingBuilder.bind(topicQueue2()).to(topicExchage()).with("topic.#");//李四接收所有员工薪资信息
}
/**
* Fanout模式 交换机Exchange
* 与指定交换机绑定的所有队列都可以接收到消息
*
* 任何发送到Fanout Exchange的消息都会被转发到与该Exchange绑定(Binding)的所有Queue上。
1.可以理解为路由表的模式
2.这种模式不需要RouteKey
3.这种模式需要提前将Exchange与Queue进行绑定,一个Exchange可以绑定多个Queue,一个Queue可以同多个Exchange进行绑定。
4.如果接受到消息的Exchange没有与任何Queue绑定,则消息会被抛弃。
* */
@Bean
public FanoutExchange fanoutExchage(){
return new FanoutExchange(FANOUT_EXCHANGE);
}
@Bean
public Binding FanoutBinding1() {
return BindingBuilder.bind(topicQueue1()).to(fanoutExchage());
}
@Bean
public Binding FanoutBinding2() {
return BindingBuilder.bind(topicQueue2()).to(fanoutExchage());
}
/**
* Header模式 交换机Exchange
* */
@Bean
public HeadersExchange headersExchage(){
return new HeadersExchange(HEADERS_EXCHANGE);
}
@Bean
public Queue headerQueue() {
return new Queue(HEADER_QUEUE, true);
}
@Bean
public Queue headerQueue1() {
return new Queue(HEADER_QUEUE1, true);
}
@Bean
public Queue headerQueue2() {
return new Queue(HEADER_QUEUE2, true);
}
@Bean
public Binding headerBinding() {
Map<String, Object> map = new HashMap<String, Object>();//共同接受到消息
map.put("type", "wechat");
map.put("type", "message");
return BindingBuilder.bind(headerQueue()).to(headersExchage()).whereAll(map).match();
}
@Bean
public Binding headerBinding1() {
Map<String, Object> map = new HashMap<String, Object>();//微信接受消息
map.put("type", "wechat");
return BindingBuilder.bind(headerQueue1()).to(headersExchage()).whereAny(map).match();
}
@Bean
public Binding headerBinding2() {
Map<String, Object> map = new HashMap<String, Object>();//短信接受消息
map.put("type", "message");
return BindingBuilder.bind(headerQueue2()).to(headersExchage()).whereAny(map).match();
}
}
MQSender
package com.rabbitmq;/**
* @author :Hj
* @date 2020/7/23
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MQSender {
private static Logger log = LoggerFactory.getLogger(MQSender.class);
@Autowired
AmqpTemplate amqpTemplate ;
public void sendDirect() {
String sendMsg = "I Love You";
System.out.println("发送内容为" + sendMsg);
amqpTemplate.convertAndSend("helloQueue", sendMsg);
}
public void sendTopic() {
log.info("发送薪资信息:");
String sendMsg ="员工张三薪资10000元";
String sendMsg2 ="经理李四薪资15000元";
amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key1", sendMsg);
amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key2", sendMsg2);
}
public void sendFanout() {
String msg = "通知,通知,所有人员到会议室开会";
log.info("send fanout message:"+msg);
amqpTemplate.convertAndSend(MQConfig.FANOUT_EXCHANGE, "", msg);
}
public void sendHeader() {
String msg = "闯红灯,扣分六分";
log.info("发送消息:"+msg);
MessageProperties properties = new MessageProperties();
properties.setHeader("type", "wechat");
properties.setHeader("type", "message");
Message obj = new Message(msg.getBytes(), properties);
amqpTemplate.convertAndSend(MQConfig.HEADERS_EXCHANGE, "", obj);
}
}
MQReceiver:
package com.rabbitmq;/**
* @author :Hj
* @date 2020/7/23
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class MQReceiver {
private static Logger log = LoggerFactory.getLogger(MQReceiver.class);
@RabbitListener(queues=MQConfig.helloQueue)
public void process(String message) {
System.out.println("接收到短信内容为: " + message);
}
@RabbitListener(queues=MQConfig.TOPIC_QUEUE1)
public void receiveTopic1(String message) {
log.info("员工张三收到通知内容为:"+message);
}
@RabbitListener(queues=MQConfig.TOPIC_QUEUE2)
public void receiveTopic2(String message) {
log.info("经理李四收到通知内容为:"+message);
}
@RabbitListener(queues=MQConfig.HEADER_QUEUE)
public void receiveHeaderQueue(byte[] message) {
log.info(" 共同接收到信息为:"+new String(message));
}
@RabbitListener(queues=MQConfig.HEADER_QUEUE1)
public void receiveHeaderQueue1(byte[] message) {
log.info("微信接收到信息为:"+new String(message));
}
@RabbitListener(queues=MQConfig.HEADER_QUEUE2)
public void receiveHeaderQueue2(byte[] message) {
log.info("短信接收到信息为:"+new String(message));
}
}