Spring Boot integrates RabbitMQ

Application scenario

1. Asynchronous processing

Scenario: after registration, users need to send e-mails and text messages after successful registration. There are two traditional methods:

  • Serial mode: after the registration information is written into the database, send the email of successful registration. After the email is sent successfully, send the SMS of successful registration. After the above three tasks are completed, the information of successful registration will be returned to the client. The problem is that e-mail and SMS are not necessary. It is just a notification. The serial mode will make the client wait for unnecessary waiting time.

  • Parallel method: after the registration information is written into the database, the email and SMS with successful registration are sent at the same time. After the above three tasks are completed, the information of successful registration will be returned to the client. The parallel method can improve the processing time accordingly.

  • Message queuing (Publish/Subscribe): write the registration information into the database and directly return the successful registration information to the client. Then, the message of sending the mail with successful registration and the message of sending the SMS with successful registration are sent to exchange. Exchange then distributes the message to two queues, which asynchronously notify the corresponding consumers to consume.

2. Application decoupling

Scenario: Double 11 is a shopping crazy festival. When users place an order, the order system needs to notify the inventory system. The traditional practice is that the order system calls the interface of the inventory system.

This approach has a disadvantage: when the inventory system fails, the call of the order system will fail, resulting in the failure of the whole request. High coupling between order system and inventory system.

After introducing the message queue ("Hello World!"):

  • Order system: after the user places an order, the order system completes the persistence processing, writes the message to the message queue, and returns the success of the user's order.

  • Inventory system: message queue sends messages to the inventory system, and the inventory system performs corresponding operations. Even if the inventory system fails, the message queue can ensure the reliable delivery of messages without message loss.

3. Flow peak shaving

Scenario: in the second kill activity, if the user directly accesses the application, the application will hang up due to excessive traffic. In order to solve this problem, message queues are usually added to the application front end.

Join the message queue ("Hello World!") to:

  • The number of active people can be controlled. If the number of order information exceeds the threshold specified by MQ, the new order information will be discarded directly.

  • It can alleviate the crushing of applications by high traffic in a short time. The system only interfaces with MQ, so the system will only consume one message sent by MQ in turn, and there will be no scenario of multiple requests accessing the system at the same time, resulting in system crash.

The specific implementation process is as follows:

  1. After receiving the user request, the server writes MQ first. If the number of messages written to MQ exceeds the preset maximum value of MQ, the user request will be discarded directly or jump to the error page.

  2. The second kill system performs business processing in turn according to the messages sent by the message queue.

Spring Boot integrates RabbitMQ

Spring Boot integrates RabbitMQ, which is very convenient to operate. Because Spring Boot further encapsulates RabbitMQ, and the spring framework naturally supports the AMQP protocol of RabbitMQ, Spring Boot provides very friendly support for RabbitMQ.

1. Basic environment construction

  1. Spring Boot version: 2.2.5.RELEASE

  2. Introduce dependency < dependency > < groupid > org. Springframework. Boot < / groupid > < artifactid > spring boot starter AMQP < / artifactid > < / dependency > copy code in pom.xml

  3. Create a Virtual host. Multiple virtual hosts can be created in a RabbitMQ Server. It is recommended that   A system or a service creates a corresponding Virtual host  , The Virtual host naming corresponds to the system, which is similar to the concept of Database in the Database (one system creates one Database). If producers and consumers want to communicate through RabbitMQ Server, they must bind the same Virtual host, and then connect with the Virtual host to produce and consume messages. The newly created Virtual host can only be accessed by guest, because guest is a guest user with the highest permission and can access all virtual hosts, including the root Virtual host (/).

  4. Create User * * it is recommended that a system create a corresponding User, and the * * User name corresponds to the system. The reason why a system corresponds to a Virtual host and a User is to make the system independent and non-interference with each other. Note: Exchange and message queues do not need to be created manually in the RabbitMQ console, but can be created in the program code.

  5. The User's permission to bind to the Virtual host just created is No access and cannot access any Virtual host. Click the User name to be bound in the table

  6. Configure application.ymlspring:  # rabbitmq configuration   rabbitmq:  # IP   host: localhost  # port   port:   five thousand six hundred and seventy-two  # user name   username: postilhub  # password   password:   one hundred and twenty-three thousand four hundred and fifty-six  # Virtual host   Virtual host: / postilhub copy code

  7. Inject rabbittemplate after establishing a connection with RabbitMQ Server, Spring will automatically instantiate a rabbittemplate object, which can be injected when used@ Autowired   private RabbitTemplate rabbitTemplate; Copy code

2. "Hello World!" model

Producer development

@Test
public void produce() {
    //  When sending a single message, the first parameter is the queue name and the second parameter is the message content
    rabbitTemplate.convertAndSend("queue", "Hello World!");
}

Note: in the above code, although the producer specifies a queue, if the queue does not exist, the queue will not be created because the producer specifies the queue.   Producers cannot create queues  , Because if there is no consumer consumption message in a queue, there is no meaning of existence. Therefore, only when the consumer exists and listens to the queue, if the queue does not exist, it will be created.

Consumer development

@Component
@RabbitListener(queuesToDeclare = @Queue(value = "queue", durable = "false", autoDelete = "true"))
public class Consumer {

    /**
     * @param message The parameter message is the content of the message
     */
    @RabbitHandler
    public void consume(String message) {
        System.out.println(message);
    }
    
}
  • @RabbitListener: indicates that the class / method is a consumer, and specifies the queue that the consumer listens to. If the queue does not exist, the queue will be created. At the same time, you can also set the characteristics of the queue, such as durable, autoDelete, exclusive, etc. true means on and false means off. For queues created by default, durable is true, and autoDelete and exclusive are false.

  • @RabbitHandler: indicates the callback method of the consumer when MQ is sent to the consumer.

3. Work queues model

Producer development

@Test
public void produce() {
    // Circularly publish multiple messages
    for (int i = 0; i < 10; i++) {
        rabbitTemplate.convertAndSend("queue", "Work Model" + i);
    }
}

Consumer development

@Component
public class Consumer {

    // Consumer 1
    @RabbitListener(queuesToDeclare = @Queue("queue"))
    public void consume1(String message) {
        System.out.println("consumer1:" + message);
    }

    // Consumer 2
    @RabbitListener(queuesToDeclare = @Queue("queue"))
    public void consume2(String message) {
        System.out.println("consumer2:" + message);
    }

}

Note: when @ RabbitListener is used on the method, there is no need to use @ RabbitHandler.

4. Publish/Subscribe model

Producer development

@Test
public void produce() {
    // The first parameter is the switch name, the second parameter is the queue name ("" indicates the random name of the queue, which is used to create a temporary queue), and the third parameter is the message content
    rabbitTemplate.convertAndSend("fanout", "", "Publish/Subscribe Model");
}

Note: in the above code, although the manufacturer specifies the switch, the switch cannot be created. The principle is the same as that of the queue. The creation of the switch also depends on the consumer.

Consumer development

@Component
public class Consumer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    // Create a temporary queue and listen
                    value = @Queue,
                    // The first parameter of the temporary queue binding switch is the switch name, and the second parameter is the switch type
                    exchange = @Exchange(value = "fanout", type = "fanout")
            )
    })
    public void consume1(String message) {
        System.out.println("consumer1:" + message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "fanout", type = "fanout")
            )
    })
    public void consume2(String message) {
        System.out.println("consumer2:" + message);
    }

}

The queue name of the temporary queue is randomly generated by RabbitMQ and automatically deleted after all messages are sent to consumers.

5. Routing model

Producer development

@Test
public void produce() {
    // The first parameter is the switch name, the second parameter is the switch RoutingKey, and the third parameter is the message content
    rabbitTemplate.convertAndSend("direct", "rabbit.info", "Routing Model");
}

Consumer development

@Component
public class Consumer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    // Create a temporary queue and listen
                    value = @Queue,
                    // Temporary queue binding switch (the default type of switch is direct, which can not be set)
                    exchange = @Exchange(value = "direct", type = "direct"),
                    // Multiple routingkeys can be set for temporary queues
                    key = {"rabbit.info", "rabbit.error"}
            )
    })
    public void consume1(String message) {
        System.out.println("consumer1:" + message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "direct"),
                    key = {"rabbit.info"}
            )
    })
    public void consume2(String message) {
        System.out.println("consumer2:" + message);
    }

}

6. Topics model

1. Producer development

@Test
public void produce() {
    // The first parameter is the switch name, the second parameter is the switch RoutingKey, and the third parameter is the message content
    rabbitTemplate.convertAndSend("topic", "rabbit.info", "Topic Model");
}

2. Consumer development

@Component
public class Consumer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    // Create a temporary queue and listen
                    value = @Queue,
                    // Temporary queue binding switch (name and value are the same)
                    exchange = @Exchange(name = "topic", type = "topic"),
                    // Multiple routingkeys can be set for temporary queues, and wildcards can be used
                    key = {"rabbit.#", "rabbit.*"}
            )
    })
    public void consume1(String message) {
        System.out.println("consumer1:" + message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "topic", type = "topic"),
                    key = {"rabbit.*"}
            )
    })
    public void consume2(String message) {
        System.out.println("consumer2:" + message);
    }

}

Original link: https://juejin.cn/post/7001427618209726478

If you think this article is helpful, you can pay attention to my official account, scan the code below, pay attention to "w programming diary" and get more Java data.

Tags: Spring Boot Programmer architecture

Posted on Sun, 05 Dec 2021 07:30:05 -0500 by phpknight