RabbitMQ四种Exchange详情及案例

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));
		}



}

猜你喜欢

转载自blog.csdn.net/jungeCSND/article/details/107541232