Basic concept of RabbitMQ and simple demonstration of binding strategy

First of all, let's understand two nouns

JMS

Java Message Service, a set of message service standards defined by Java, conforms to JMS standard specifications, and is a general Java Message Service

MOM

Message Oriented Middleware is a middleware product that conforms to message development standards and specifications, such as ActiveMQ, RabbitMQ, Kafka, etc. Middleware products can provide message storage mechanism, message sending and consumption services, and message cache processing. Products that conform to MOM specifications and can be accessed by relying on JMS standard specifications can be called JMS Provider

Benefits of MQ

  • decoupling

    The original way of network call among multiple components is now changed to MQ for asynchronous communication of messages. If a consumer system goes offline, the impact is just that the message backlog is not consumed in MQ

  • Recoverability

    When some components of the system fail, the whole business system will not be affected. MQ can ensure that the queued messages can still be consumed after the component recovers

  • asynchronous communication

    Message queuing provides an asynchronous processing mechanism, which can improve the user's experience (for example, after the user places an order, the order system directly returns the successful result of placing an order, then encapsulates the data into MQ, and finally enters the database)

  • Peak processing

    MQ can make key components withstand huge pressure during peak visit (for example, the order system will be stored in MQ queue, and will not directly visit the consumer end. The consumer end controls the processing speed by pulling, so that the flow tends to be stable, achieving the purpose of peak cutting and valley filling)

  • Expansibility

    Due to the low coupling between components, it is convenient to increase the message queuing and processing frequency

The principle of RabbitMQ

  • Broker

    The process of receiving client connection and realizing AMQP message queuing and routing (the RabbitServer we started)

  • Vhost

    Virtual host. There can be multiple Exchange and queues in a VH. When multiple different users use the same RabbitMQ service (Broker), multiple VHS are divided

  • Exchange

    Accept the sender's message and route it to different queues according to the Binding rule

  • Queue

    Where messages are stored. Multiple senders can send messages to a Queue, and multiple consumers can consume messages of a Queue, which is essentially a buffer. It follows the FIFO (first in first out) processing mechanism. In the Queue of RabbitMQ, message persistence or automatic deletion can be set

  • Channel

    Because it is unrealistic to establish a large number of TCP connections, AMQP (Advanced message queuing protocol) stipulates that all messages must be sent through channels

Binding policy

  • Direct

    It is a point-to-point switch. The sender sends a message to MQ. After receiving the message, the MQ direct switch will determine which queue the message will be sent to according to the routing key. The receiver needs to monitor a queue (by registering the queue monitor) and consume the message when the queue status changes. Register queue listener needs to provide switch information, queue information and routing key information

    Sender

    yaml

    server:
      port: 8282
    
    spring:
      rabbitmq:
        host: 192.168.49.142
        port: 5672
        username: guest
        password: guest
        virtual-host: /
    

    pom

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    direct

    @Component
    public class DirectMessagePush {
    
       /**
        * Inject RabbitMQ logic template
        */
       @Resource
       private AmqpTemplate amqpTemplate;
    
       public void sendMessage(Order order) {
          /**
           * order-exchange Specific exchanger
           * order Routing key
           */
          this.amqpTemplate.convertAndSend("order-exchange", "order", order);
       }
    
    }
    

    controller

    @Controller
    public class Send {
    
       @Resource
       private DirectMessagePush directMessagePush;
    
       @GetMapping("/order")
       @ResponseBody
       public String sendOrder() {
          Order order = new Order();
          order.setId(1);
          order.setTotalPrice(18000.00);
          List<Item> items = new ArrayList<>();
          for (int i = 0; i < 5; i++) {
             Item item = new Item();
             item.setId(1 + i);
             item.setPrice(2000.00 + i * 200);
             item.setProductName("Apple 16");
             item.setRemark("2019 16 inch");
             items.add(item);
          }
          order.setItems(items);
    
          this.directMessagePush.sendMessage(order);
          return "SUCCESS !";
       }
    
    }
    

    Receiver

    yaml

    server:
      port: 8181
    
    spring:
      rabbitmq:
        host: 192.168.49.142
        port: 5672
        username: guest
        password: guest
        virtual-host: /
        listener:
          direct:
            retry:
              enabled: true
              max-attempts: 10
    

    pom

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- AMQP Plug in groups for development spring boot Access compliance AMQP Agreed MQ Product dependent initiators -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    consumer

    /**
     * @RabbitListener RabbitMQ Listener class of
     * 		bindings Binding policy
     * @QueueBinding Declare specific binding policies
     * 		value Specific bound queue
     * 		exchange Exchange corresponding to queue
     * 		key Specific routing key bound
     * @Queue Specific queue description
     * 		name Queue name, consumer concerned, publisher not concerned
     * 		autoDelete
     * 			"true" RabbitMQ automatically deletes the queue when it is not listened by any consumers
     *			"false" As long as the queue is created and never deleted, RabbitMQ saves messages that are not consumed and waits for other consumer listeners to process them
     * @Exchange Specific exchanger
     * 		name Name of exchanger
     *	    autoDelete Delete the switch when there is no queue bound to it
     * 		type Type of exchanger
     */
    @RabbitListener(bindings = {
          @QueueBinding(
                value = @Queue(name = "order-queue", autoDelete = "false"),
                exchange = @Exchange(name = "order-exchange", type = "direct", autoDelete = "false"),
                key = "order"
          )
    })
    @Component
    public class OrderMassage {
    
       /**
        * @param order news
        * @RabbitHandler Mark the current method as the method of consuming messages
        * This method will be registered on MQ, listen to the queue of MQ, and consume automatically when messages appear in the queue
        * <p>
        * Consumer method cannot have return value!
        */
       @RabbitHandler
       public void doSomething(Order order) {
          /**
           * Related business
           */
          System.out.println("order = ------------------>>> " + order);
       }
    
    }
    
  • Fanout

    Broadcast switch. Send the received message broadcast to all queues matched by the binding. The process switch will not match the Routing Key, so there is no need to provide the Routing Key information in the message. The receiver needs to monitor a queue (by registering the queue listener) and consume the message when the queue status changes. Register queue listener needs to provide switch information and queue information

    Sender

    yaml

    server:
      port: 8282
    
    spring:
      rabbitmq:
        host: 192.168.49.142
        port: 5672
        username: guest
        password: guest
        virtual-host: /
    

    pom

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    fanout

    @Component
    public class FanoutPublisher {
    
       @Resource
       private AmqpTemplate amqpTemplate;
    
       public void sendStr(String str) {
          // The middle occupation parameter cannot be defaulted!
          this.amqpTemplate.convertAndSend("fanout-exchange", "", str);
       }
    
    }
    

    controller

    @Controller
    public class Send {
    
       @Resource
       private FanoutPublisher fanoutPublisher;
    
       @GetMapping("/fanout")
       @ResponseBody
       public String sendStr() {
          this.fanoutPublisher.sendStr("Broadcast notice:... ...");
          return "OK";
       }
    
    }
    

    Receiver

    yaml

    server:
      port: 8181
    
    spring:
      rabbitmq:
        host: 192.168.49.142
        port: 5672
        username: guest
        password: guest
        virtual-host: /
        listener:
          direct:
            retry:
              enabled: true
              max-attempts: 10
    

    pom

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- AMQP Plug in groups for development spring boot Access compliance AMQP Agreed MQ Product dependent initiators -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    consumer1

    /**
     * Consumer 1 of broadcast queue
     */
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(name = "log-fanout1", autoDelete = "false"),
                    exchange = @Exchange(name = "fanout-exchange", autoDelete = "false", type = "fanout")
            )
    })
    @Component
    public class Person1 {
    
        @RabbitHandler
        public void fanoutHandler(String srt) {
            System.out.println("srt1 ----------------------------> " + srt);
        }
    
    }
    

    consumer2

    /**
     * Consumers of broadcast queue 2
     */
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(name = "log-fanout2", autoDelete = "false"),
                    exchange = @Exchange(name = "fanout-exchange", autoDelete = "false", type = "fanout")
            )
    })
    @Component
    public class Person2 {
    
        @RabbitHandler
        public void fanoutHandler(String srt) {
            System.out.println("srt2 ----------------------------> " + srt);
        }
    
    }
    
  • Topic

    Subject switch. Also known as the rule matching switch. By using the customized matching rules to decide which queues messages are stored in, the switches in MQ will decide which queue messages should be sent to according to the Routing Key; the receiver needs to be responsible for monitoring a queue (by registering the queue listener) and consuming messages when the queue status changes. Register queue listener needs to provide switch information, queue information and Routing Key information

    Sender

    yaml

    server:
      port: 8282
    
    spring:
      rabbitmq:
        host: 192.168.49.142
        port: 5672
        username: guest
        password: guest
        virtual-host: /
    

    pom

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    topic

    /**
     * Send log message
     */
    @Component
    public class LogPublisher {
    
       @Resource
       private AmqpTemplate amqpTemplate;
    
       public void sendLog(String log) {
          Random random = new Random();
          int num = random.nextInt(10000);
    
          String routingKey = "";
          if (num % 5 == 0) {
             routingKey = "char.log.info";
          }
          if (num % 5 == 1) {
             routingKey = "char.log.warn";
          }
          if (num % 5 == 2) {
             routingKey = "char.log.error";
          } else {
             routingKey = "char.log.char";
          }
          System.out.println("routingKey --------------------> " + routingKey);
    
          this.amqpTemplate.convertAndSend("topic-exchange", routingKey, log);
    
       }
    
    }
    

    Receiver

    yaml

    server:
      port: 8181
    
    spring:
      rabbitmq:
        host: 192.168.49.142
        port: 5672
        username: guest
        password: guest
        virtual-host: /
        listener:
          direct:
            retry:
              enabled: true
              max-attempts: 10
    

    pom

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- AMQP Plug in groups for development spring boot Access compliance AMQP Agreed MQ Product dependent initiators -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    

    consumer1

    /**
     * Consume all level logs
     */
    @RabbitListener(bindings = {
          @QueueBinding(
                value = @Queue(name = "topic-log-all", autoDelete = "false"),
                exchange = @Exchange(name = "topic-exchange", autoDelete = "false", type = "topic"),
                key = "*.log.*"
          )
    })
    @Component
    public class All {
    
       @RabbitHandler
       public void logHandler(String info) {
          System.out.println("all --------------------------->" + info);
       }
    
    }
    

    consumer2

    /**
     * Consumption error level log
     */
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(name = "topic-log-error", autoDelete = "false"),
                    exchange = @Exchange(name = "topic-exchange", autoDelete = "false", type = "topic"),
                    key = "*.log.error"
            )
    })
    @Component
    public class Error {
    
        @RabbitHandler
        public void logHandler(String error) {
            System.out.println("error --------------------------->" + error);
        }
    
    }
    

    consumer3

    ...

    consumer4

    ...

    Note: it's time to develop the message consumer. The consumer method cannot have a return value (that is, the method described by @ RabbitHandler does not have a return value)

Tags: Spring RabbitMQ Java kafka

Posted on Sun, 21 Jun 2020 03:46:55 -0400 by hastishah