RabbitMQ中交换机的几种模式

目录

简述

交换机模式

Fanout模式

Direct模式

Topic模式

Headers模式


简述

生产者不直接跟队列打交道,而是通过交换机。交换机类似于生产者和队列直接的一个管理者,它将生产的消息分配给对应的队列。

前期准备pom.xml中的依赖


  org.springframework.boot
  spring-boot-starter-amqp

具体整合详细可见 整合Springboot和RabbitMQ


交换机模式

Fanout模式

        又叫广播模式,类似于一个微信公众号,当公众号发布消息的时候所有关注该公众号的用户都能收到消息,FanoutExchange的功能就类似与公众号。

测试步骤

  1. Config中配置两个队列分别为03和04在配置一个FanoutExchange交换机

  2. 将交换机和两个队列03,04分别绑定

  3. 发送消息给交换机

  4. 分别接收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中交换机的几种模式_第1张图片

 

RabbitMQ交换机绑定关系

RabbitMQ中交换机的几种模式_第2张图片

Direct模式

        直接模式,该模式主要是利用路由键(routing key),交换机通过该键连接对应的队列将信息放入对应的队列中

测试步骤

  1. Config中配置两个队列分别为01和02在配置一个DirectExchange交换机

  2. 将交换机和队列01以及路由键red绑定,将交换机和队列02以及路由键green和red绑定

  3. 发送消息给交换机对应的路由键

  4. 绑定该键的队列接收消息

配置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中交换机的几种模式_第3张图片

RabbitMQ中交换机的几种模式_第4张图片

RabbitMQ绑定关系 

RabbitMQ中交换机的几种模式_第5张图片

Topic模式

        类似于direct模式,属于direct模式的扩展,允许routing key使用* 和 # 作为通配符

        *表示匹配精确的一个

        #表示匹配零个或多个

        例如

        ①#.queue.#        ②*.queue.#

        ask.abc.queue.ccd.aac        被①匹配不被②

        abc.queue.acc                被①②匹配

测试步骤

  1. Config中配置两个队列分别为05和06再配置一个TopicExchange交换机

  2. 将交换机和队列05以及路由键#.queue.#绑定,将交换机和队列06以及路由键*.queue.#绑定

  3. 发送第一则消息给交换机对应的路由键是ask.abc.queue.ccd.aac;

  4. 发送第二则消息给交换机对应的路由键是abc.queue.acc;

  5. 收到第一则消息:队列05

  6. 收到第二则消息:队列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中交换机的几种模式_第6张图片

RabbitMQ绑定关系 

RabbitMQ中交换机的几种模式_第7张图片  

Headers模式

        该模式不使用routing key而是使用键值对的匹配方式来实现交换机和队列的匹配

        该模式效率比routing key的效率低并且实现比较复杂

测试步骤

  1. Config中配置两个队列分别为08和09再配置一个HeaderExchange交换机

  2. Map map = new HashMap<>();
    map.put("color","red");
    map.put("speed","low");
  3. 将交换机和队列08绑定并设置whereAny(map)

  4. 将交换机和队列09绑定并设置whereAll(map)

  5. MessageProperties properties = new MessageProperties();
    properties.setHeader("color","red");
    properties.setHeader("speed","low");
    Message message =new Message(msg.getBytes(),properties);
    //发送第一则消息给交换机并设置头信息,此时发送的是Message对象
    rabbitTemplate.convertAndSend("headerExchange","",message);
  6. MessageProperties properties = new MessageProperties();
    properties.setHeader("color","red");
    Message message =new Message(msg.getBytes(),properties);
    //发送第二则消息给交换机并设置头信息,此时发送的是Message对象
    rabbitTemplate.convertAndSend("headerExchange","",message);
  7. 收到第一则消息:队列08,队列09

  8. 收到第二则消息:队列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绑定关系 

RabbitMQ中交换机的几种模式_第8张图片

你可能感兴趣的:(日常学习,RabbitMQ,rabbitmq,分布式,java)