1. 创建一个springboot项目,pom文件中引入RocketMQ关键依赖
注意:使用SpringBoot集成时,要非常注意版本
org.apache.rocketmq
rocketmq-spring-boot-starter
2.2.2
org.apache.rocketmq
rocketmq-client
org.apache.rocketmq
rocketmq-client
4.9.5
2. springboot的启动类
package com.roy.rocketmq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RocketMQSBApplication {
public static void main(String[] args) {
SpringApplication.run(RocketMQSBApplication.class,args);
}
}
3. 在application.properties中写rocketMQ的配置
rocketmq.name-server=192.168.31.5:9876
#rocketmq.name-server=127.0.0.1:9876
rocketmq.producer.group=springBootGroup
#如果这里不配,那就需要在消费者的注解中配。
#rocketmq.consumer.topic=
rocketmq.consumer.group=testGroup
server.port=9000
4. 声明生产者,直接使用RocketMQTemplate进行消息发送。
package com.roy.rocketmq.basic;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class SpringProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
public SendResult sendMessage(String topic,String msg){
SendResult sendResult = rocketMQTemplate.syncSend(topic, msg);
return sendResult;
}
public void sendMessageInTransaction(String topic,String msg) throws InterruptedException {
String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
for (int i = 0; i < 10; i++) {
//尝试在Header中加入一些自定义的属性。
Message message = MessageBuilder.withPayload(msg)
.setHeader(RocketMQHeaders.TRANSACTION_ID,"TransID_"+i)
//发到事务监听器里后,这个自己设定的TAGS属性会丢失。但是上面那个属性不会丢失。
.setHeader(RocketMQHeaders.TAGS,tags[i % tags.length])
//MyProp在事务监听器里也能拿到,为什么就单单这个RocketMQHeaders.TAGS拿不到?这只能去调源码了。
.setHeader("MyProp","MyProp_"+i)
.build();
String destination =topic+":"+tags[i % tags.length];
//这里发送事务消息时,还是会转换成RocketMQ的Message对象,再调用RocketMQ的API完成事务消息机制。
SendResult sendResult = rocketMQTemplate.sendMessageInTransaction(destination, message,destination);
System.out.printf("%s%n", sendResult);
Thread.sleep(10);
}
}
}
5. 声明一个消费者
1.创建一个类实现RocketMQListener接口,注意泛型的使用,可以为具体的类型,如果想拿到消息的其他参数可以写成MessageExt
2.类上添加注解@Component和@RocketMQMessageListener
3.@RocketMQMessageListener(topic = "TestTopic", consumerGroup = "MyConsumerGroup")
4.topic指定消费的主题,consumerGroup指定消费组,一个主题可以有多个消费者组,一个消息可以被多个不同的组的消费者都消费
package com.roy.rocketmq.basic;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.ExtRocketMQConsumerConfiguration;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* 注意下@RocketMQMessageListener这个注解的其他属性
**/
@Component
@RocketMQMessageListener(consumerGroup = "MyConsumerGroup", topic = "TestTopic",consumeMode= ConsumeMode.CONCURRENTLY,messageModel= MessageModel.BROADCASTING)
public class SpringConsumer implements RocketMQListener {
@Override
public void onMessage(String message) {
System.out.println("Received message : "+ message);
}
}
6. 写一个测试方法,测试发送一条消息
@Resource private SpringProducer producer; @Test public void send() { SendResult test = producer.sendMessage("test", "hello,rocketMq..."); System.out.println(test); }
7. 测试消费消息
启动项目,一直监听消息队列。一旦有消息发送则会消费消息。
package com.roy.rocketmq;
import com.alibaba.fastjson.TypeReference;
import com.roy.rocketmq.domain.OrderPaidEvent;
import com.roy.rocketmq.domain.ProductWithPayload;
import com.roy.rocketmq.domain.User;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQLocalRequestCallback;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.MimeTypeUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringRocketTest {
@Resource
private RocketMQTemplate rocketMQTemplate;
@Test
public void sendMessageTest(){
String springTopic="TestTopic";
//发送字符消息
SendResult sendResult = rocketMQTemplate.syncSend(springTopic, "Hello, World!");
System.out.printf("syncSend1 to topic %s sendResult=%s %n", springTopic, sendResult);
sendResult = rocketMQTemplate.syncSend(springTopic, new User().setUserAge((byte) 18).setUserName("Kitty"));
System.out.printf("syncSend1 to topic %s sendResult=%s %n", springTopic, sendResult);
sendResult = rocketMQTemplate.syncSend(springTopic, MessageBuilder.withPayload(
new User().setUserAge((byte) 21).setUserName("Lester")).setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE).build());
System.out.printf("syncSend1 to topic %s sendResult=%s %n", springTopic, sendResult);
//发送对象消息
rocketMQTemplate.asyncSend(springTopic, new OrderPaidEvent("T_001", new BigDecimal("88.00")), new SendCallback() {
@Override
public void onSuccess(SendResult var1) {
System.out.printf("async onSucess SendResult=%s %n", var1);
}
@Override
public void onException(Throwable var1) {
System.out.printf("async onException Throwable=%s %n", var1);
}
});
//发送指定TAG的消息
rocketMQTemplate.convertAndSend(springTopic + ":tag0", "I'm from tag0"); // tag0 will not be consumer-selected
System.out.printf("syncSend topic %s tag %s %n", springTopic, "tag0");
rocketMQTemplate.convertAndSend(springTopic + ":tag1", "I'm from tag1");
System.out.printf("syncSend topic %s tag %s %n", springTopic, "tag1");
//同步发送消息并且返回一个String类型的结果。
String replyString = rocketMQTemplate.sendAndReceive(springTopic, "request string", String.class);
System.out.printf("send %s and receive %s %n", "request string", replyString);
//同步发送消息并且返回一个Byte数组类型的结果。
byte[] replyBytes = rocketMQTemplate.sendAndReceive(springTopic, MessageBuilder.withPayload("request byte[]").build(), byte[].class, 3000);
System.out.printf("send %s and receive %s %n", "request byte[]", new String(replyBytes));
//同步发送一个带hash参数的请求(排序消息),并返回一个User类型的结果
User requestUser = new User().setUserAge((byte) 9).setUserName("requestUserName");
User requestUser2 = new User().setUserAge((byte) 9).setUserName("requestUserName");
User requestUser3 = new User().setUserAge((byte) 9).setUserName("requestUserName");
User requestUser4 = new User().setUserAge((byte) 9).setUserName("requestUserName");
User replyUser = rocketMQTemplate.sendAndReceive(springTopic, requestUser, User.class, "order-id");
User replyUser2 = rocketMQTemplate.sendAndReceive(springTopic, requestUser2, User.class, "order-id");
User replyUser3 = rocketMQTemplate.sendAndReceive(springTopic, requestUser3, User.class, "order-id");
User replyUser4 = rocketMQTemplate.sendAndReceive(springTopic, requestUser4, User.class, "order-id");
System.out.printf("send %s and receive %s %n", requestUser, replyUser);
//同步发送一个带延迟级别的消息(延迟消息),并返回一个泛型结果
ProductWithPayload replyGenericObject = rocketMQTemplate.sendAndReceive(springTopic, "request generic",
new TypeReference>() {
}.getType(), 30000, 2);
System.out.printf("send %s and receive %s %n", "request generic", replyGenericObject);
//异步发送消息,返回String类型结果。
rocketMQTemplate.sendAndReceive(springTopic, "request string", new RocketMQLocalRequestCallback() {
@Override public void onSuccess(String message) {
System.out.printf("send %s and receive %s %n", "request string", message);
}
@Override public void onException(Throwable e) {
e.printStackTrace();
}
});
//异步发送消息,并返回一个User类型的结果。
rocketMQTemplate.sendAndReceive(springTopic, new User().setUserAge((byte) 9).setUserName("requestUserName"), new RocketMQLocalRequestCallback() {
@Override public void onSuccess(User message) {
System.out.printf("send user object and receive %s %n", message.toString());
}
@Override public void onException(Throwable e) {
e.printStackTrace();
}
}, 5000);
//发送批量消息
List msgs = new ArrayList();
for (int i = 0; i < 10; i++) {
msgs.add(MessageBuilder.withPayload("Hello RocketMQ Batch Msg#" + i).
setHeader(RocketMQHeaders.KEYS, "KEY_" + i).build());
}
SendResult sr = rocketMQTemplate.syncSend(springTopic, msgs, 60000);
System.out.printf("--- Batch messages send result :" + sr);
}
}
一个RocketMQTemplate实例只能包含一个生产者,也就只能往一个Topic下发送消息。如果需要往另外一个Topic下发送消息,就需要通过@ExtRocketMQTemplateConfiguration()注解另外声明一个子类实例。
package com.roy.rocketmq.config;
import org.apache.rocketmq.spring.annotation.ExtRocketMQConsumerConfiguration;
import org.apache.rocketmq.spring.annotation.ExtRocketMQTemplateConfiguration;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
@ExtRocketMQTemplateConfiguration()
//@ExtRocketMQConsumerConfiguration(topic="stock_consumer_group")
public class ExtRocketMQTemplate extends RocketMQTemplate {
}
对于事务消息机制,最关键的事务监听器需要通过@RocketMQTransactionListener注解注入到Spring容器当中。在这个注解当中可以通过rocketMQTemplateBeanName属性,指向具体的RocketMQTemplate子类。
发送消息代码
public void sendMessageInTransaction(String topic,String msg) throws InterruptedException { String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"}; for (int i = 0; i < 10; i++) { //尝试在Header中加入一些自定义的属性。 Message
message = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TRANSACTION_ID,"TransID_"+i) //发到事务监听器里后,这个自己设定的TAGS属性会丢失。但是上面那个属性不会丢失。 .setHeader(RocketMQHeaders.TAGS,tags[i % tags.length]) //MyProp在事务监听器里也能拿到,为什么就单单这个RocketMQHeaders.TAGS拿不到?这只能去调源码了。 .setHeader("MyProp","MyProp_"+i) .build(); String destination =topic+":"+tags[i % tags.length]; //这里发送事务消息时,还是会转换成RocketMQ的Message对象,再调用RocketMQ的API完成事务消息机制。 SendResult sendResult = rocketMQTemplate.sendMessageInTransaction(destination, message,destination); System.out.printf("%s%n", sendResult); Thread.sleep(10); } }
监听事务代码:
package com.roy.rocketmq.config; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener; import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener; import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState; import org.apache.rocketmq.spring.support.RocketMQHeaders; import org.apache.rocketmq.spring.support.RocketMQUtil; import org.springframework.messaging.Message; import org.springframework.messaging.converter.StringMessageConverter; import java.util.concurrent.ConcurrentHashMap; /** * @description: 事务消息监听器 * 关于@RocketMQTransactionListener 这个注解,有点奇怪。2.0.4版本中,是需要指定txProducerGroup指向一个消息发送者组。不同的组可以有不同的事务消息逻辑。 * 但是到了2.1.1版本,只能指定rocketMQTemplateBeanMame,也就是说如果你有多个发送者组需要有不同的事务消息逻辑,那就需要定义多个RocketMQTemplate。 * 而且这个版本中,虽然重现了我们在原生API中的事务消息逻辑,但是测试过程中还是发现一些奇怪的特性,用的时候要注意点。 **/ //@RocketMQTransactionListener(txProducerGroup = "springBootGroup2") //@RocketMQTransactionListener(rocketMQTemplateBeanName = "ExtRocketMQTemplate") @RocketMQTransactionListener() public class MyTransactionImpl implements RocketMQLocalTransactionListener { private ConcurrentHashMap