RabbitMQ (four) switch Exchanges

RabbitMQ (four) switch Exchanges


5 switches

5.1 Exchanges

5.1.1 Exchanges concept

​ The core idea of ​​the RabbitMQ message delivery model: the message produced by the producer will not be sent directly to the queue, the producer can only send the message to the exchange (exchange) , the work content of the exchange on the one hand receives the message from the producer, and on the other hand aspect, pushes the received message into the queue. On the other hand, pushing messages into the queue requires knowing the message processing strategy, which is determined by the type of switch .

5.1.2 Types of Exchanges

​ There are a total of the following types

​ Direct type (direct), topic (topic), title (headers), fanout (fanout)

Exchanges type alias routingKey Strategy
Fanout broadcast mode empty string broadcasts the received message to all queues it knows about
Direct direct mode black… The message is withdrawn to the routingKey queue it is bound to. When the keys of multiple bound queues are the same, the performance is similar to the fanout type.
Topic theme mode Combinations of words, separated by dots
* (asterisk) can replace one word, # (pound sign) can replace zero or more words
Messages can be sent through wildcards.
When a queue binding key is #, the queue will receive all data, which is a bit like fanout.
If are no # and * in the queue binding key, then the queue binding type is direct up

5.1.3 Default Exchanges

​ When we sent messages before, the reason why it was possible was to use the default switch, which ""was identified by an empty string.

/**
 * 1. 交换机
 * 2. 队列名
 * 3. 参数 消息持久化(保存在磁盘上)
 * 4. 消息
 */
channel.basicPublish("",QueueName.Ack_Queue.getName(), MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes(StandardCharsets.UTF_8));

The first parameter is the name of the switch, an empty string means the default or unnamed switch.

It can be seen in the UI management interface

insert image description here

5.2 Temporary queue

​ We used a queue before, and there will be a queue name, so if we need an empty queue with a random name when we connect to rabbitMQ , then we can create a queue with a random name, but when we disconnect the consumption The queue will be deleted automatically .

​ The way to create a temporary queue is as follows

/**
 *  声明一个临时队列
 *  生成一个零时队列,队列的名称是随机的
 *  当消费者断开与队列的连接时,队列就自动删除
 */
String queueName = channel.queueDeclare().getQueue();

Created and can be seen in the UI

insert image description here

5.3 Bindings

​ Bingding is a bridge between exchange and queue. It tells us which queue the exchange is bound to. It is a bound relationship value.

insert image description here

5.4 Fanout fan-out mode

​ The type of fanout is very simple, it broadcasts all received messages to all queues it knows.

insert image description here

5.4.1 Fanout actual structure diagram

insert image description here

The binding relationship between Logs and temporary queues is shown in the figure below

insert image description here

5.4.2 Fanout actual combat code

  1. Consumer 1 ReceiveLogs01

    /**
     * 消费者负责消费消息
     */
    public class ReceiveLogs01 {
          
          
    
      public static void main(String[] args) throws Exception{
          
          
        Channel channel = RabbitMqUtil.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(ExchangeName.Log_Exchange.getName(), "fanout");
        /**
             *  声明一个临时队列
             *  生成一个零时队列,队列的名称是随机的
             *  当消费者断开与队列的连接时,队列就自动删除
             */
        String queueName = channel.queueDeclare().getQueue();
    
        //绑定交换机与队列
        channel.queueBind(queueName,ExchangeName.Log_Exchange.getName(), "");
        //等待接收消息
        DeliverCallback deliverCallback=(consumerTag,message)->{
          
          
          System.out.println("打印接收到的消息:"+new String(message.getBody(),"UTF-8"));
        };
        System.out.println("消费者A-正在接收消息");
        channel.basicConsume(queueName,true,deliverCallback,(consumerTag,message)->{
          
          });
      }
    }
    
  2. Consumer 2 ReceiveLogs02

    /**
     * 消费者负责消费消息
     */
    public class ReceiveLogs02 {
          
          
    
      public static void main(String[] args) throws Exception{
          
          
        Channel channel = RabbitMqUtil.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(ExchangeName.Log_Exchange.getName(), "fanout");
        /**
             *  声明一个临时队列
             *  生成一个零时队列,队列的名称是随机的
             *  当消费者断开与队列的连接时,队列就自动删除
             */
        String queueName = channel.queueDeclare().getQueue();
    
        //绑定交换机与队列
        channel.queueBind(queueName,ExchangeName.Log_Exchange.getName(), "");
        //等待接收消息
        DeliverCallback deliverCallback=(consumerTag,message)->{
          
          
          System.out.println("打印接收到的消息:"+new String(message.getBody(),"UTF-8"));
        };
        System.out.println("消费者B-正在接收消息");
        channel.basicConsume(queueName,true,deliverCallback,(consumerTag,message)->{
          
          });
      }
    }
    
  3. Producer EmitLog

    /**
     * 发消息给交换机
     */
    public class EmitLog {
          
          
    
      public static void main(String[] args)throws Exception {
          
          
        Channel channel = RabbitMqUtil.getChannel();
        channel.exchangeDeclare(ExchangeName.Log_Exchange.getName(), "fanout");
        Scanner scanner = new Scanner(System.in);
    
        while (scanner.hasNext()){
          
          
          String message = scanner.next();
          channel.basicPublish(ExchangeName.Log_Exchange.getName(), "",null,message.getBytes("UTF-8"));
          System.out.println("生产者发出消息: "+message);
        }
    
      }
    }
    

5.4.3 Actual Screenshots

  1. producer

    insert image description here

  2. Consumer A

    insert image description here

  3. Consumer B

    insert image description here

5.5 Direct Direct mode

​ In the last part we shared information with all consumers, but if we want to send messages to different consumers, the exchange type of fanout cannot bring us much flexibility, here we will To use the Direct type for replacement, the strategy of this working method is: the message will only go to the routingKey queue it is bound to.

insert image description here

5.5.1 Direct actual combat structure diagram

insert image description here

The Direct_Logs binding queue relationship is as follows

insert image description here

5.5.2 Direct actual combat code

  1. Consumer 1 ReceiveLogsDirect01

    public class ReceiveLogsDirect01 {
          
          
    
        public static void main(String[] args) throws Exception{
          
          
            Channel channel = RabbitMqUtil.getChannel();
            //声明交换机
            channel.exchangeDeclare(ExchangeName.Direct_Logs.getName(), BuiltinExchangeType.DIRECT);
            //声明一个队列
            channel.queueDeclare(QueueName.Console_Queue.getName(), false,false,false,null);
            channel.queueBind(QueueName.Console_Queue.getName(), ExchangeName.Direct_Logs.getName(),"info");
            channel.queueBind(QueueName.Console_Queue.getName(), ExchangeName.Direct_Logs.getName(),"warning");
    
            //接收消息
            //等待接收消息
            DeliverCallback deliverCallback=(consumerTag, message)->{
          
          
                System.out.println("打印接收到的消息:"+new String(message.getBody(),"UTF-8"));
            };
    
            System.out.println("消费者A-正在接收消息 (接收info,warning)");
            //消费者接收消息
            channel.basicConsume(QueueName.Console_Queue.getName(), true,deliverCallback,consumerTag->{
          
          });
    
        }
    }
    
  2. Consumer 2 ReceiveLogsDirect02

    public class ReceiveLogsDirect02 {
          
          
    
        public static void main(String[] args) throws Exception{
          
          
            Channel channel = RabbitMqUtil.getChannel();
            //声明交换机
            channel.exchangeDeclare(ExchangeName.Direct_Logs.getName(), BuiltinExchangeType.DIRECT);
            //声明一个队列
            channel.queueDeclare(QueueName.Disk_Queue.getName(), false,false,false,null);
            channel.queueBind(QueueName.Disk_Queue.getName(), ExchangeName.Direct_Logs.getName(),"error");
    //        channel.queueBind(QueueName.Disk_Queue.getName(), ExchangeName.Direct_Logs.getName(),"warning");
    
            //接收消息
            //等待接收消息
            DeliverCallback deliverCallback=(consumerTag, message)->{
          
          
                System.out.println("打印接收到的消息:"+new String(message.getBody(),"UTF-8"));
            };
    
            System.out.println("消费者B-正在接收消息 (接收error)");
            //消费者接收消息
            channel.basicConsume(QueueName.Disk_Queue.getName(), true,deliverCallback,consumerTag->{
          
          });
        }
    }
    
  3. ProducerEmitLogTwo

    public class EmitLogTwo {
          
          
    
      public static void main(String[] args)throws Exception {
          
          
        Channel channel = RabbitMqUtil.getChannel();
        channel.exchangeDeclare(ExchangeName.Direct_Logs.getName(), BuiltinExchangeType.DIRECT);
        Scanner scanner = new Scanner(System.in);
    
        while (true){
          
          
          System.out.print("请输入你需要发送的日志类型:");
          String logType = scanner.next();
          if("warning".equals(logType)||"info".equals(logType)||"error".equals(logType)){
          
          
            System.out.print("请输入你需要发送的消息:");
            String message = scanner.next();
            channel.basicPublish(ExchangeName.Direct_Logs.getName(), logType,null,message.getBytes("UTF-8"));
            System.out.println("生产者发出消息: "+message);
          }else {
          
          
            System.out.println("类型输入错误!请重新输入");
            continue;
          }
        }
      }
    }
    

5.5.3 Actual Screenshots

  1. producer

    insert image description here

  2. Consumer A

    insert image description here

  3. Consumer B

    insert image description here

5.5.4 Multiple bindings

​ When the type of exchange is direct, but the keys of multiple queues bound to it are the same , in this case, although the bound type is direct, its performance is somewhat similar to fanout , similar to the broadcast mode, sending The message will be received by the same binding key.

5.5.5 routingKey without binding relationship

​ When the exchange sends a message to a routingKey that is not bound to a queue (queue), the message will eventually be discarded because there is no binding relationship.

5.6 Topic theme mode

​ Although the direct switch solves some of the limitations, the topic type can use wildcards on the basis of direct and bind routingkey, which is more flexible.

insert image description here

Topic requirements

​ The binding key of the topic switch cannot be filled in at will, and must meet certain requirements

  1. Must be a list of words, separated by dots

  2. wildcards can be used

    * (asterisk) can replace a word

    # (pound sign) can replace zero or more words

5.6.1 Topic combat structure diagram

insert image description here

Topic_Logs binding queue relationship is as follows

insert image description here

5.6.2 Topic combat code

  1. Consumer 1 ReceiveLogsTopic01

    /**
     * 主题模式消费者
     */
    public class ReceiveLogsTopic01 {
          
          
    
      public static void main(String[] args)throws Exception{
          
          
        Channel channel = RabbitMqUtil.getChannel();
    
        //声明交换机
        channel.exchangeDeclare(ExchangeName.Topic_Logs.getName(), BuiltinExchangeType.TOPIC);
        //声明队列
        channel.queueDeclare(QueueName.Q1_Queue.getName(), false,false,false,null);
        //绑定队列
        channel.queueBind(QueueName.Q1_Queue.getName(), ExchangeName.Topic_Logs.getName(), "*.orange.*");
    
        System.out.println("主题模式消费者T1正在等待消息... (*.orange.*)");
    
        //接收消息
        channel.basicConsume(QueueName.Q1_Queue.getName(),true,(consumerTag,message)->{
          
          
          System.out.println("打印接收到的消息:"+new String(message.getBody(),"UTF-8"));
        },consumerTag->{
          
          });
      }
    }
    
    
  2. Consumer 2 ReceiveLogsTopic02

    /**
     * 主题模式消费者
     * 通配符 *表示一个单词,#代表一个或多个单
     */
    public class ReceiveLogsTopic02 {
          
          
    
      public static void main(String[] args)throws Exception{
          
          
        Channel channel = RabbitMqUtil.getChannel();
    
        //声明交换机
        channel.exchangeDeclare(ExchangeName.Topic_Logs.getName(), BuiltinExchangeType.TOPIC);
        //声明队列
        channel.queueDeclare(QueueName.Q2_Queue.getName(), false,false,false,null);
        //绑定队列
        channel.queueBind(QueueName.Q2_Queue.getName(), ExchangeName.Topic_Logs.getName(), "*.*.rabbit");
        channel.queueBind(QueueName.Q2_Queue.getName(), ExchangeName.Topic_Logs.getName(), "lazy.#");
    
        System.out.println("主题模式消费者T2正在等待消息... (*.*.rabbit)(lazy.#)");
    
        //接收消息
        channel.basicConsume(QueueName.Q2_Queue.getName(),true,(consumerTag,message)->{
          
          
          System.out.println("打印接收到的消息:"+new String(message.getBody(),"UTF-8"));
        },consumerTag->{
          
          });
      }
    }
    
  3. Producer EmitLogThree

    public class EmitLogThree {
          
          
    
      public static void main(String[] args)throws Exception {
          
          
        Channel channel = RabbitMqUtil.getChannel();
        channel.exchangeDeclare(ExchangeName.Topic_Logs.getName(), BuiltinExchangeType.TOPIC);
        Scanner scanner = new Scanner(System.in);
    
        while (true){
          
          
          System.out.print("请输入你需要发送的routingKey:");
          String logType = scanner.next();
          System.out.print("请输入你需要发送的消息:");
          String message = scanner.next();
          channel.basicPublish(ExchangeName.Topic_Logs.getName(), logType,null,message.getBytes("UTF-8"));
          System.out.println("生产者发出消息: "+message);
        }
    
      }
    }
    

5.6.3 Actual Screenshots

  1. producer

    insert image description here

  2. Consumer A

    insert image description here

  3. Consumer B

    insert image description here

Note : When a queue binding key is #, then this queue will receive all data, which is a bit like fanout.
If are no # and * in the queue binding key, then the queue binding type is like direct.

Guess you like

Origin blog.csdn.net/qq_27331467/article/details/126131135