SpringBoot+RabbitMQ learning notes RabbitMQ message persistence processing

Posted by mslinuz on Wed, 29 Apr 2020 11:52:35 +0200

I. Introduction

 

There is an autoDelete attribute in both @ Queue and @ Exchange annotations. The value is a string of boolean type. For example: autoDelete = "false".

@Queue: whether to delete the queue automatically after all consumer clients are disconnected: true: delete, false: do not delete.

@Exchange: automatically delete the exchange when all binding queues are not in use: true: delete, false: do not delete.

When all consumer clients disconnect, and we persist the RabbitMQ message, then the messages that are not consumed are stored in the memory of the RabbitMQ server. If the RabbitMQ server is shut down, the data that is not consumed will be lost.

Write the code below to try the message persistence processing of RabbitMQ.

II. Configuration file

This test uses the error log message queue written in the previous blog. Here are two projects to create, one as a producer and one as a consumer.

Producer configuration:

server.port=8883

spring.application.name=hello-world
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.thymeleaf.cache=false

#Set switch name
mq.config.exchange=log.direct
#Set the routing key of the error queue
mq.config.queue.error.routing.key=log.error.routing.key

Consumer configuration

server.port=8884

spring.application.name=lesson1

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

#Set switch name
mq.config.exchange=log.direct
#Set error queue name
mq.config.queue.error=log.error
#Set error routing key
mq.config.queue.error.routing.key=log.error.routing.key

III. producers

package com.example.rabbitdurableprovider;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Author:aijiaxiang
 * Date:2020/4/26
 * Description:send message
 */
@Component
public class DurableSender {

    @Autowired
    private AmqpTemplate amqpTemplate;

    //exChange exchanger
    @Value("${mq.config.exchange}")
    private String exChange;

    //routingkey Routing key
    @Value("${mq.config.queue.error.routing.key}")
    private String routingKey;
    /**
     * How to send a message
     * @param msg
     */
    public void send(String msg){
        //Send message to message queue
        //Parameter 1: switch name
        //Parameter 2: route key
        //Parameter 3: message
        this.amqpTemplate.convertAndSend(exChange,routingKey,msg);

    }
}

IV. prepare consumers

Here, the autoDelete property in the @ Queue in the consumer service configuration is set to true, that is, it is not persistent. For a while, test to see how the message Queue without persistence works after all consumer servers are disconnected.

package com.ant.rabbitdurableconsumer;

import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

/**
 * Author:aijiaxiang
 * Date:2020/4/26
 * Description:Message Receiver 
 * @RabbitListener bindings:Bind queue
 * @QueueBinding  value: Name of binding queue
 *                  exchange: Configure switch
 * @Queue : value: Configure queue name
 *          autoDelete:Is it a temporary queue that can be deleted
 * @Exchange value:Name the switch
 *           type:Specify specific exchanger type
 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.error}",autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.DIRECT),
                key = "${mq.config.queue.error.routing.key}"
        )
)
public class DurableErrorReceiver {

    /**
     * Message receiving method adopts message queue monitoring mechanism
     * @param msg
     */
    @RabbitHandler
    public void process(String msg){
        System.out.println("error-receiver: "+msg);
    }
}

 

V. write test class

Here, a dead loop is written to continuously send messages to the message queue, and the sending number is recorded with the variable "false".

package com.example.amqp;

import com.example.helloworld.HelloworldApplication;
import com.example.rabbitdurableprovider.DurableSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * Author:aijiaxiang
 * Date:2020/4/26
 * Description:
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = HelloworldApplication.class)
public class QueueTest {

    @Autowired
    private DurableSender durableSender;

    @Test
    public void test3() throws InterruptedException {
        int flag = 0;
        while (true){
            flag++;
            Thread.sleep(2000);
            durableSender.send("hello--"+flag);

        }


    }
}

First start the consumer server, then start the test class, the console outputs the following information, and then close tomcat to simulate the consumer server failure. It can be seen here that "failure" occurs when the message received by the consumer stays in Article 81, but the producer is still continuously sending messages to the consumer.

At this time, restart tomcat, and the consumer receives the message again, but it starts from message 111, so all the messages between 81-111 are lost.

 

Modify the code of the consumer service, set autoDelete to "false", and persist the RabbitMQ message.

@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.error}",autoDelete = "false"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.DIRECT),
                key = "${mq.config.queue.error.routing.key}"
        )
)

After modification, restart the consumer server and call the test method again. Then shut down the consumer server and simulate a "failure.". At this time, you see that the 15th server "fails" after receiving the message.

 

Restart the consumer server. You can see that as soon as the server is started, the consumer reads the message in RabbitMQ when the server "fails" from the message queue. The message is not lost, and the message persistence of RabbitMQ is successful.

 

OK! The above is the RabbitMQ message persistence processing learned today. If there is something wrong, please correct it!

Topics: Java RabbitMQ Spring Junit Tomcat