RocketMQ-Spring graduated two years ago, why can it become the most popular messa in the Spring ecology?

Head picture.png

Author | RocketMQ Official WeChat
Source | Alibaba Cloud Native Official Account

In January 2019, RocketMQ-Spring, which has been incubated for 6 months, officially graduated as a sub-project of Apache RocketMQ, and released the first Release version 2.0.1. This project encapsulates the RocketMQ client using Spring Boot, allowing users to write codes through simple annotations and standard Spring Messaging API to send and consume messages. At that time, RocketMQ community students asked Spring community students to review the RocketMQ-Spring code, leading to a story about RocketMQ and Spring Boot .

Two years later, RocketMQ-Spring officially released 2.2.0. During this period, RocketMQ-Spring has iterated several versions. The Spring Cloud Stream RocketMQ Binder and Spring Cloud Bus RocketMQ based on RocketMQ-Spring have been posted on Spring's official website . Spring evangelist baeldung introduced how to use RocketMQ- Spring , more and more students at home and abroad have begun to use RocketMQ-Spring to send and receive messages. The number of stars in the RocketMQ-Spring warehouse has surpassed Spring-Kafka and Spring-AMQP in just two years (Note: Both are produced by Spring Community maintenance), becoming one of the most popular ecological projects of Apache RocketMQ.

1.png

The popularity of RocketMQ-Spring is due to the perfect fit between RocketMQ, which supports rich business scenarios, and Spring, a microservice ecosystem, on the one hand, and on the other hand, it is inseparable from RocketMQ-Spring's strict compliance with the Spring Messaging API specification and support for rich message types. .

Follow the Spring Messaging API specification

Spring Messaging provides a set of abstract APIs to specify the mode of message sender and message receiver. Different message middleware providers can provide their own Spring implementation in this mode: What needs to be implemented on the message sender is a XXXTemplate The form of Java Bean, combined with Spring Boot's automatic configuration options, provides multiple different methods of sending messages; on the consumer side of the message is a XXXMessageListener interface (the implementation usually uses an annotation to declare a message-driven POJO), and provides a callback method To monitor and consume messages, this interface can also use Spring Boot's automation options and some customized properties.

1. The sender

RocketMQ-Spring provides corresponding APIs based on the Spring Messaging API specification and combined with RocketMQ's own features. On the sending end of the message, RocketMQ-Spring completes the sending of the message by implementing RocketMQTemplate. As shown in the figure below, RocketMQTemplate inherits the AbstractMessageSendingTemplate abstract class to support the Spring Messaging API standard message conversion and sending methods. These methods will eventually be delegated to the doSend method, and the doSend method will eventually call syncSend, which is implemented by DefaultMQProducer.

2.png

In addition to the methods in the Spring Messaging API specification, RocketMQTemplate also implements some methods of the RocketMQ native client to support richer message types. It’s worth noting that, compared to native clients who need to build RocketMQ Message (such as serializing objects into byte arrays into Message objects), RocketMQTemplate can directly send objects, strings or byte arrays as parameters (object serialization The operation is built-in by RocketMQ-Spring), and the corresponding Schema can be agreed on the consumer side to send and receive normally.

RocketMQTemplate Send API:
    SendResult syncSend(String destination, Object payload) 
    SendResult syncSend(String destination, Message<?> message)
    void asyncSend(String destination, Message<?> message, SendCallback sendCallback)
    void asyncSend(String destination, Message<?> message, SendCallback sendCallback)
    ……

2. Consumer

On the consumer side, you need to implement a class that contains @RocketMQMessageListener annotations (you need to implement the RocketMQListener interface, implement the onMessage method, and configure the topic, consumerGroup and other attributes in the annotations), and this Listener will be placed in the DefaultRocketMQListenerContainer container object one-to-one , The container object will encapsulate the RocketMQListener into the concurrency or sequential interface implementation inside the specific RocketMQ according to the consumption mode (concurrency or sequence). Create a RocketMQ DefaultPushConsumer object in the container, start and monitor the customized Topic message, complete the conversion of the agreed Schema object, and call back to the onMessage method of the Listener.

@Service
@RocketMQMessageListener(topic = "${demo.rocketmq.topic}", consumerGroup = "string_consumer", selectorExpression = "${demo.rocketmq.tag}")
public class StringConsumer implements RocketMQListener<String> {
    @Override
    public void onMessage(String message) {
        System.out.printf("------- StringConsumer received: %s \n", message);
    }
}

In addition to this Push interface, in the latest 2.2.0 version, RocketMQ-Spring implements RocketMQ Lite Pull Consumer . Through the configuration of the consumer in the configuration file, the Recevie method of RocketMQTemplate can be used to initiate Pull messages.

配置文件resource/application.properties:

rocketmq.name-server=localhost:9876
rocketmq.consumer.group=my-group1
rocketmq.consumer.topic=test

Pull Consumer代码:

while(!isStop) {
    List<String> messages = rocketMQTemplate.receive(String.class);
    System.out.println(messages);
}

Rich message types

RocketMQ Spring message type support is fully aligned with RocketMQ native client, including synchronous/asynchronous/one-way, sequence, delay, batch, transaction, and Request-Reply messages. Here, we mainly introduce more special transaction messages and request-reply messages.

1. Transaction message

The transaction message of RocketMQ is different from the transaction message in Spring Messaging, and it still uses the scheme of RocketMQ's native transaction message. As shown below, when sending a transaction message, you need to implement a class that contains @RocketMQTransactionListener annotations, and implement the executeLocalTransaction and checkLocalTransaction methods to complete the execution of the local transaction and check the execution result of the local transaction.

// Build a SpringMessage for sending in transaction
Message msg = MessageBuilder.withPayload(..)...;
// In sendMessageInTransaction(), the first parameter transaction name ("test")
// must be same with the @RocketMQTransactionListener's member field 'transName'
rocketMQTemplate.sendMessageInTransaction("test-topic", msg, null);

// Define transaction listener with the annotation @RocketMQTransactionListener
@RocketMQTransactionListener
class TransactionListenerImpl implements RocketMQLocalTransactionListener {
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        // ... local transaction process, return bollback, commit or unknown
        return RocketMQLocalTransactionState.UNKNOWN;
    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        // ... check transaction status and return bollback, commit or unknown
        return RocketMQLocalTransactionState.COMMIT;
    }
}

In version 2.1.0, RocketMQ-Spring refactored the implementation of transaction messages. As shown in the figure below, each group in the old version corresponds to a TransactionProducer, but in the new version, each RocketMQTemplate corresponds to a TransactionProducer, thus solving The problem of concurrently using multiple transaction messages. When users need to use multiple transaction messages in a single process, they can use ExtRocketMQTemplate to complete (in general, it is recommended to use one RocketMQTemplate for one process, and ExtRocketMQTemplate can be used in scenarios where multiple Producer / LitePullConsumers are needed in the same process, which can be ExtRocketMQTemplate Specify the nameserver, group, etc. configuration different from the standard template RocketMQTemplate), and specify rocketMQTemplateBeanName as the BeanName of ExtRocketMQTemplate in the corresponding RocketMQTransactionListener annotation.

3.png

2. Request-Reply message

In version 2.1.0, RocketMQ-Spring began to support Request-Reply messages. Request-Reply message means that the upstream service enters the state of waiting to be notified after the message is delivered, until the consumer returns the result and returns it to the sender. In RocketMQ-Spring, the sender uses the sendAndReceivce method of RocketMQTemplate to send, as shown below, there are two main methods: synchronous and asynchronous. In asynchronous mode, the callback is performed by implementing RocketMQLocalRequestCallback.

// 同步发送request并且等待String类型的返回值
String replyString = rocketMQTemplate.sendAndReceive("stringRequestTopic", "request string", String.class);

// 异步发送request并且等待User类型的返回值
rocketMQTemplate.sendAndReceive("objectRequestTopic", new User("requestUserName",(byte) 9), new RocketMQLocalRequestCallback<User>() {
    @Override public void onSuccess(User message) {
        ……
    }

    @Override public void onException(Throwable e) {
        ……
    }
});

On the consumer side, you still need to implement a class that contains @RocketMQMessageListener annotations, but the interface that needs to be implemented is the RocketMQReplyListener<T, R> interface (the ordinary message is the RocketMQListener<T> interface), where T represents the type of the received value, and R represents the return Value type, the interface needs to implement the onMessage method with return value, and the content of the return value is returned to the corresponding Producer.

@Service
@RocketMQMessageListener(topic = "stringRequestTopic", consumerGroup = "stringRequestConsumer")
public class StringConsumerWithReplyString implements RocketMQReplyListener<String, String> {
    @Override
    public String onMessage(String message) {
        ……
        return "reply string";
    }
}

RocketMQ-Spring follows the Spring Convention over configuration (Convention over configuration) concept, through the starter (Spring Boot Starter), the introduction of dependencies in the pom file (groupId: org.apache.rocketmq, artifactId: rocketmq-spring-boot-starter) ) Can integrate all the functions of all RocketMQ clients in Spring Boot, and send and receive messages through simple annotations.  There are more detailed usage and frequently asked questions in RocketMQ-Spring Github Wiki .

According to statistics, since the release of the first official version of RocketMQ-Spring, RocketMQ-Spring has completed 16 bug fixes and 37 imporvements, including transaction message reconstruction, message filtering, message serialization, multi-instance RocketMQTemplate optimization and other important optimizations. Welcome more friends to participate in the construction of the RocketMQ community. The story of RocketMQ and Spring Boot continues...

Guess you like

Origin blog.51cto.com/13778063/2618994