This article discusses how to use RocketMQ Binder to subscribe and publish Spring Cloud application messages.
introduce
RocketMQ It is an open source distributed message system. Based on the highly available distributed cluster technology, it provides low latency and highly reliable message publishing and subscription services, which are widely used in many fields, including asynchronous communication decoupling, enterprise solutions, financial payment, telecommunications, e-commerce, express logistics, advertising and marketing, social networking, instant communication, mobile applications, mobile games, video Internet of things, Internet of vehicles, etc.
RocketMQ is an open-source distributed message middleware of Alibaba in 2012, which has been donated to the Apache Software Foundation and became the top project of Apache on September 25, 2017. As a domestic middleware that has experienced the baptism of "super project" of Alibaba double 11 for many times and has stable and outstanding performance, it has been used by more and more domestic enterprises in recent years with its high performance, low delay and high reliability.
RocketMQ features
- It is a message middleware of queue model, with the characteristics of high performance, high reliability, high real-time, distributed, etc
- Producer, Consumer and queue can be distributed
- Producer sends messages to some queues in turn. The queue set is called Topic. If a Consumer does broadcast consumption, a Consumer instance consumes all queues corresponding to the Topic. If cluster consumption is done, multiple Consumer instances consume the queue set corresponding to the Topic on average
- Can guarantee strict message order
- Support pull and push message modes
- Efficient subscriber level scalability
- Real time message subscription mechanism
- 100 million message stacking capacity
- Support multiple message protocols, such as JMS, OpenMessaging, etc
- Less dependence
Spring Cloud Stream
Spring Cloud Stream is a framework for building message driven microservices.
Spring Cloud Stream provides a unified abstraction of the configuration of message middleware, and pubs / sub, consumer groups, semantics, and stateful partition are supported by these unified models.
The core components of Spring Cloud Stream include binders, binding s and messages. Applications interact with binders through inputs or outputs, and bind through our configuration. Binders interact with middleware. Message is the unified data specification format for data exchange.
- Binding: includes Input Binding and Output Binding.
Binding provides a bridge between the message middleware and the Provider and Consumer provided by the application. It realizes that developers only need to use the Provider or Consumer of the application to produce or consume data, and blocks the contact between developers and the underlying message middleware.
- Binder: a component integrated with external message middleware to create Binding. Each message middleware has its own binder implementation.
For example, Kafka implements KafkaMessageChannelBinder, RabbitMQ implements RabbitMessageChannelBinder, and RocketMQ implements rocketmgmessagechannelbinder.
- Message: it is a module in the Spring Framework. Its function is the programming model of unified message.
For example, the corresponding model of message Messaging includes a message body Payload and message Header.
Spring cloud stream official website
Setting up and deploying RocketMQ in Window
download
The current latest version is 4.6.0
Download it and unzip it to: D:\rocketmq directory. It's better not to take space and too deep in the directory, otherwise the service may report an error
Start NameServer service
Before startup, you need to configure the system environment, otherwise an error will be reported.
Please set the ROCKETMQ_HOME variable in your environment!
System environment variable name: rocketmq · home
Configure environment variables according to the directory you unzipped. For example, my variable value is: D:\rocketmq
Enter the window command window, enter the directory D:\rocketmq\bin, and execute
start mqnamesrv.cmd
As above, NameServer starts successfully. Do not close the window during use.
Start Broker service
Enter bin directory and enter
start mqbroker.cmd -n localhost:9876
The above ip+port is the service address and port of rocketmq.
If you run the above command, the following error may be reported. Cannot find or load main class
If this happens, open bin -- > runbroker.cmd, modify% CLASSPATH% to% CLASSPATH%
Save to execute the above command again. After successful execution, prompt boot success to indicate success.
Example
This example implements the publishing and subscription receiving of three kinds of messages.
Create RocketMQ message producer
Create Ali rocketmq producer project with port 28081
- pom.xml add dependency
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud-alibaba</artifactId> <groupId>com.easy</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>ali-rocketmq-producer</artifactId> <packaging>jar</packaging> <dependencies> <!--rocketmq rely on--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> </dependency> <!--web rely on--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- Configure the Binding information of Output and validate it with @ EnableBinding annotation
application.yml configuration
server: port: 28081 spring: application: name: ali-rocketmq-producer cloud: stream: rocketmq: binder: # RocketMQ server address name-server: 127.0.0.1:9876 bindings: output1: {destination: test-topic1, content-type: application/json} output2: {destination: test-topic2, content-type: application/json} management: endpoints: web: exposure: include: '*' endpoint: health: show-details: always
ArProduceApplication.java
@SpringBootApplication @EnableBinding({MySource.class}) public class ArProduceApplication { public static void main(String[] args) { SpringApplication.run(ArProduceApplication.class, args); } }
- Message producer service
MySource.java
package com.easy.arProduce; import org.springframework.cloud.stream.annotation.Output; import org.springframework.messaging.MessageChannel; public interface MySource { @Output("output1") MessageChannel output1(); @Output("output2") MessageChannel output2(); }
SenderService.java
package com.easy.arProduce; import org.apache.rocketmq.spring.support.RocketMQHeaders; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.support.MessageBuilder; import org.springframework.stereotype.Service; import org.springframework.util.MimeTypeUtils; @Service public class SenderService { @Autowired private MySource source; /** * Send string * * @param msg */ public void send(String msg) { Message message = MessageBuilder.withPayload(msg) .build(); source.output1().send(message); } /** * Send string with tag * * @param msg * @param tag */ public void sendWithTags(String msg, String tag) { Message message = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TAGS, tag) .build(); source.output1().send(message); } /** * Sending objects * * @param msg * @param tag * @param <T> */ public <T> void sendObject(T msg, String tag) { Message message = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TAGS, tag) .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) .build(); source.output2().send(message); } }
Write TestController.java controller for testing
package com.easy.arProduce; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "test") public class TestController { @Autowired SenderService senderService; @RequestMapping(value = "/send", method = RequestMethod.GET) public String send(String msg) { senderService.send(msg); return "String message sent successfully!"; } @RequestMapping(value = "/sendWithTags", method = RequestMethod.GET) public String sendWithTags(String msg) { senderService.sendWithTags(msg, "tagStr"); return "belt tag String message sent successfully!"; } @RequestMapping(value = "/sendObject", method = RequestMethod.GET) public String sendObject(int index) { senderService.sendObject(new Foo(index, "foo"), "tagObj"); return "Object Object message sent successfully!"; } }
Create RocketMQ message consumer
Create Ali rocketmq consumer project with port 28082
- pom.xml add dependency
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud-alibaba</artifactId> <groupId>com.easy</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>ali-rocketmq-consumer</artifactId> <packaging>jar</packaging> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-Configure the Binding information of Input and validate it with @ EnableBinding annotation
application.yml configuration
server: port: 28082 spring: application: name: ali-rocketmq-consumer cloud: stream: rocketmq: binder: name-server: 127.0.0.1:9876 #rocketmq service address bindings: input1: {consumer.orderly: true} #Is it sorted? input2: {consumer.tags: tagStr} #Subscription string with tag value of tagStr input3: {consumer.tags: tagObj} #Subscription string with tag value of tabObj bindings: input1: {destination: test-topic1, content-type: text/plain, group: test-group1, consumer.maxAttempts: 1} input2: {destination: test-topic1, content-type: application/plain, group: test-group2, consumer.maxAttempts: 1} input3: {destination: test-topic2, content-type: application/plain, group: test-group3, consumer.maxAttempts: 1} management: endpoints: web: exposure: include: '*' endpoint: health: show-details: always
ArConsumerApplication.java
package com.easy.arConsumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.stream.annotation.EnableBinding; @SpringBootApplication @EnableBinding({MySource.class}) public class ArConsumerApplication { public static void main(String[] args) { SpringApplication.run(ArConsumerApplication.class, args); } }
- Message consumer service
MySource.java
package com.easy.arConsumer; import org.springframework.cloud.stream.annotation.Input; import org.springframework.messaging.SubscribableChannel; public interface MySource { @Input("input1") SubscribableChannel input1(); @Input("input2") SubscribableChannel input2(); @Input("input3") SubscribableChannel input3(); }
ReceiveService.java
package com.easy.arConsumer; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.stereotype.Service; @Service @Slf4j public class ReceiveService { @StreamListener("input1") public void receiveInput1(String receiveMsg) { log.info("input1 Message received:" + receiveMsg); } @StreamListener("input2") public void receiveInput2(String receiveMsg) { log.info("input2 Message received:" + receiveMsg); } @StreamListener("input3") public void receiveInput3(@Payload Foo foo) { log.info("input3 Message received:" + foo); } }
Use example
Sample associated items
In this example, we create two project implementations
Ali RocketMQ producer: RocketMQ message service producer, service name: Ali RocketMQ producer, port: 28081
Ali RocketMQ consumer: RocketMQ message service consumer, service name: Ali RocketMQ producer, port: 28082
Run sample tests
First, start the Ali rocketmq producer service and Ali rocketmq consumer service
- Visit the producer address of message service: http://localhost:28081/test/send?msg=yuntian
View service consumer console, output
2019-12-04 15:37:47.859 INFO 6356 --- [MessageThread_1] com.easy.arConsumer.ReceiveService : input1 Message received: yuntian 2019-12-04 15:37:47.859 INFO 6356 --- [MessageThread_1] s.b.r.c.RocketMQListenerBindingContainer : consume C0A8096E200818B4AAC212CDA70E0014 cost: 1 ms
Indicates that string consumption is successfully consumed by input1
- Visit the producer address of message service: http://localhost:28081/test/sendWithTags?msg=tagyuntian
View service consumer console, output
2019-12-04 15:38:09.586 INFO 6356 --- [MessageThread_1] com.easy.arConsumer.ReceiveService : input2 Message received: tagyuntian 2019-12-04 15:38:09.592 INFO 6356 --- [MessageThread_1] com.easy.arConsumer.ReceiveService : input1 Message received: tagyuntian 2019-12-04 15:38:09.592 INFO 6356 --- [MessageThread_1] s.b.r.c.RocketMQListenerBindingContainer : consume C0A8096E200818B4AAC212CDFCD30015 cost: 6 ms
It means that the string with tag is successfully consumed by input2 and input1, because input1 also subscribes to test-topic1, and we do not add tag filter. By default, it means that all messages are received, so the tagyuntian string can also be successfully received
- Access the producer address of message service: http://localhost:28081/test/sendObject?index=1
View service consumer console, output
2019-12-04 15:41:15.285 INFO 6356 --- [MessageThread_1] com.easy.arConsumer.ReceiveService : input3 Message received: Foo{id=1, bar='foo'}
It indicates that input3 has successfully received the object message with tag and tagObj, while input1 has no output message. This is because the message published by sendObject uses the test Topic2 message pipeline, so it will not be published to input1 and input2 subscribers