[SpringBoot MQ Series] RabbitListener consumer use basic gestures introduction

[MQ Series] RabbitListener consumer use basic gestures introduction

Before the introduction of the rabbitmq messaging posture, since there are sending, of course you have to have consumers in SpringBoot environment, consumption can be said is relatively simple, with @RabbitListenerannotations, you can basically meet more than 90% of the business development needs

Here we look at @RabbitListenerthe most common use of gestures

I. placement

SpringBoot first create a project for subsequent presentation

Dependent configuration file pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <!-- 注意,下面这个不是必要的哦-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/libs-snapshot-local</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/libs-milestone-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-releases</id>
        <name>Spring Releases</name>
        <url>https://repo.spring.io/libs-release-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

In the application.ymlconfiguration file, add the relevant attributes of rabbitmq

spring:
  rabbitmq:
    virtual-host: /
    username: admin
    password: admin
    port: 5672
    host: 127.0.0.1

II. Consumer posture

This article will target on practicality, combining specific scenarios to demonstrate @RabbitListenerthe use of gestures, so this comment which some attribute or do not understand, please do not worry when you find reading this article, the next will come one by one

0. mock data

Consumer spending, there is no data, how to spend? So we first step, create a message producer, you can write data to exchange, for subsequent use consumer test

Benpian consumption mainly in the topic model to be explained (several other models use little difference, if there is demand, then follow padded)

@RestController
public class PublishRest {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping(path = "publish")
    public boolean publish(String exchange, String routing, String data) {
        rabbitTemplate.convertAndSend(exchange, routing, data);
        return true;
    }
}

Provides a simple interface to rest, you can specify which exchange to push data and develop key routes

1. case1: exchange, queue already exists

For consumers, they really need to manage the creation of exchange / destruction, which is defined by the sender; In general, consumers are more concerned with their own queue, including the definition and exchange queue and binding, and this a process that can be directly operated by rabbitmq console oh

Therefore, the actual development process, exchange and queue corresponding binding relationship and the possibility that already exists is very high, then the code does not need additional processing;

In this scenario, consumption data, we can say very, very simple, as follows:

/**
 * 当队列已经存在时,直接指定队列名的方式消费
 *
 * @param data
 */
@RabbitListener(queues = "topic.a")
public void consumerExistsQueue(String data) {
    System.out.println("consumerExistsQueue: " + data);
}

Annotations directly specified in the queuesparameters can, parameter values for the column name (queueName)

2. case2: queue does not exist

When the queue is autoDelete property is false, using the above scenario is more appropriate; however, when this property is true, there is no consumer queue will be automatically deleted, and this time then the above position, may get the following abnormal

Queue does not exist

Typically this scenario, we need to take the initiative to create Queue, and establish a binding relationship with the Exchange is given below @RabbitListenerrecommended posture

/**
 * 队列不存在时,需要创建一个队列,并且与exchange绑定
 */
@RabbitListener(bindings = @QueueBinding(
        value = @Queue(value = "topic.n1", durable = "false", autoDelete = "true"),
        exchange = @Exchange(value = "topic.e", type = ExchangeTypes.TOPIC),
        key = "r"))
public void consumerNoQueue(String data) {
    System.out.println("consumerNoQueue: " + data);
}

A comment, declared inside the queue, and establish the binding relationship is so magical! ! !

Note @QueueBindingannotation three properties:

  • value: @Queue annotations for declaring the queue, value is queueName, durable indicates whether the queue is persistent, autoDelete indicates whether the queue is not automatically deleted after consumers
  • exchange: @Exchange annotations for declaring exchange, type specified message delivery strategy, we are here with the way the topic
  • key: In the topic the way, this is what we know routingKey

Above, is the use of gestures in the queue does not exist, it seems not complicated

3. Case3: oh

In the core knowledge of the learning process in front rabbitmq we will know that in order to ensure data consistency, there is a message acknowledgment mechanism;

ack here mainly for the consumer end, when we want to change the default ack mode (noack, auto, manual), can be processed as follows

/**
 * 需要手动ack,但是不ack时
 *
 * @param data
 */
@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "topic.n2", durable = "false", autoDelete = "true"),
        exchange = @Exchange(value = "topic.e", type = ExchangeTypes.TOPIC), key = "r"), ackMode = "MANUAL")
public void consumerNoAck(String data) {
    // 要求手动ack,这里不ack,会怎样?
    System.out.println("consumerNoAck: " + data);
}

The above implementation is relatively simple, provided ackMode=MANUAL, manual ack

However, please note that our implementation, there is no place reflects the manual ack, which is equivalent to the same are not ack, in later tests, it can be seen when this is not ack, will find that the data has been unackedthis column when the number of Unacked exceeds the limit, it will not consume the new data

4. case4: manual ack

Although the above selection ack way, but still missing a step ack logic, let's look at how filled

/**
 * 手动ack
 *
 * @param data
 * @param deliveryTag
 * @param channel
 * @throws IOException
 */
@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "topic.n3", durable = "false", autoDelete = "true"),
        exchange = @Exchange(value = "topic.e", type = ExchangeTypes.TOPIC), key = "r"), ackMode = "MANUAL")
public void consumerDoAck(String data, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel)
        throws IOException {
    System.out.println("consumerDoAck: " + data);

    if (data.contains("success")) {
        // RabbitMQ的ack机制中,第二个参数返回true,表示需要将这条消息投递给其他的消费者重新消费
        channel.basicAck(deliveryTag, false);
    } else {
        // 第三个参数true,表示这个消息会重新进入队列
        channel.basicNack(deliveryTag, false, true);
    }
}

Note that the method adds two more arguments

  • deliveryTag: Equivalent to uniquely identify the message, for which the message is to distinguish mq ack / nak the
  • channel: Mq and conduit between the consumer, through which ack / nak

When we correct consumption, by calling the basicAckmethod can be

// RabbitMQ的ack机制中,第二个参数返回true,表示需要将这条消息投递给其他的消费者重新消费
channel.basicAck(deliveryTag, false);

When we consume fails, the message needs to be re-inserted into the queue, waiting for re-consumption, can be used basicNack

// 第三个参数true,表示这个消息会重新进入队列
channel.basicNack(deliveryTag, false, true);

5. case5: concurrent consumption

When a lot of news, a Hangchihangchi consumer spending is too slow, but my machine performance and leverage, and this time I hope parallel consumption, equivalent to the same time there are more consumers to process data

To support concurrent consumption, the following settings can be

@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "topic.n4", durable = "false", autoDelete = "true"),
        exchange = @Exchange(value = "topic.e", type = ExchangeTypes.TOPIC), key = "r"), concurrency = "4")
public void multiConsumer(String data) {
    System.out.println("multiConsumer: " + data);
}

Please note annotation of the concurrency = "4"property, which is a fixed four consumers;

In addition to the above assignment this way, there is a m-nformat represents m parallel consumers, there may be up to n

(Additional Description: This parameter explained it SimpleMessageListenerContainer, the next article will introduce it at the scene of DirectMessageListenerContainera difference)

6. Test

Messaging interface through front reservation, we request the browser: http://localhost:8080/publish?exchange=topic.e&routing=r&data=wahaha

consumption

Then look at the output, five consumers have received, especially nak initiative that consumers have been receiving the message;

(As has been print the log, so restart the application, starts the next test)

Then send a success message, ACK true manual verification, whether there will be the case above, the request command: http://localhost:8080/publish?exchange=topic.e&routing=r&data=successMsg

Then look no ack of the queue, there have been news of a unack

II. Other

Bowen series

Source Project

1. a gray Blog : https://liuyueyi.github.io/hexblog

A gray personal blog, recording all study and work in the blog, welcome to go around

2. Statement

Believe everything the book is not as good, above, is purely one of the words, due to limited personal capacity, it is inevitable omissions and mistakes, such as find a bug or have better suggestions are welcome criticism and generous gratitude

3. Scan concern

A gray blog

QrCode

Published 206 original articles · won praise 57 · views 160 000 +

Guess you like

Origin blog.csdn.net/liuyueyi25/article/details/105207235