spring-boot-rocketmq-consumer:消费者
spring-boot-rocketmq-producer:生产者
1.RocketMQ的SpringBoot版本官方starter:https://github.com/apache/rocketmq-spring,当前最新版本为2.0.3
org.apache.rocketmq
rocketmq-spring-boot-starter
2.0.3
2.新建上述Maven多模块项目,在Maven父模块spring-boot-rocketmq中引入Maven依赖,完整pom.xml如下:
子模块spring-boot-rocketmq-producer生产者和spring-boot-rocketmq-consumer消费者中引入下面
com.thinkingcao.rocketmq
spring-boot-rocketmq
0.0.1-SNAPSHOT
4.0.0
com.thinkingcao.rocketmq
spring-boot-rocketmq
0.0.1-SNAPSHOT
pom
spring-boot-rocketmq
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.1.5.RELEASE
1.8
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.apache.rocketmq
rocketmq-spring-boot-starter
2.0.3
com.alibaba
fastjson
1.2.24
org.springframework.boot
spring-boot-maven-plugin
二、创建生产者
1、生产者结构图
2、新建实体类OrderPaidEvent.java
package com.thinkingcao.rocketmq.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
@Data
@AllArgsConstructor
public class OrderPaidEvent implements Serializable {
private String orderId;
private Integer paidMoney;
}
3、新建生产者RocketMQProducer.java
package com.thinkingcao.rocketmq.producer;
import com.thinkingcao.rocketmq.entity.OrderPaidEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
*
* @desc:
* @title: RocketMQProducer
* @author: cao_wencao
* @date: 2019-06-04 17:52
* @version: 1.0
*
*/
@Slf4j
@Component
public class RocketMQProducer implements CommandLineRunner {
@Resource
private RocketMQTemplate rocketMQTemplate;
@Override
public void run(String... args) throws Exception {
log.info("-----------生产者开始生产消息-----------");
rocketMQTemplate.convertAndSend("test-topic-1", "Hello, World!");
log.info("生产者生产第一个消息完成: 主题:{}, 内容:{}","test-topic-1","Hello, World!");
rocketMQTemplate.convertAndSend("test-topic-2",
new OrderPaidEvent("orderId-0001", 88));
log.info("生产者生产第二个消息完成: 主题:{}, 内容:{}","test-topic-2",new OrderPaidEvent("orderId-0001", 88));
log.info("-----------生产者生产消息结束-----------");
}
}
4、新建application.properties配置文件
##生产者配置
# 端口
server.port=7777
# NameServer地址
rocketmq.name-server=127.0.0.1:9876
# 生产者的组名
rocketmq.producer.group=ProducerGroup
# 发送消息超时时间
rocketmq.producer.send-message-timeout=3000
# 消息最大长度
rocketmq.producer.max-message-size=4194304
rocketmq.producer.compress-message-body-threshold=4096
rocketmq.producer.retry-times-when-send-async-failed=0
rocketmq.producer.retry-next-server=true
rocketmq.producer.retry-times-when-send-failed=2
5、新建生产者启动类SpringBootRocketmqProducerApplication.java
package com.thinkingcao.rocketmq;
import com.thinkingcao.rocketmq.entity.OrderPaidEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.Resource;
/**
*
* @desc: 生产者启动类
* @auth: cao_wencao
* @date: 2019/6/4 17:40
* @param null
*
*/
@SpringBootApplication
@Slf4j
public class SpringBootRocketmqProducerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRocketmqProducerApplication.class, args);
}
}
三、创建消费者
1.、消费者结构图
2、新建实体类OrderPaidEvent.java 同生产者一样
3、新建两个消费者MyConsumer1.java和MyConsumer2.java
MyConsumer1
package com.thinkingcao.rocketmq.consumer;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
*
* @desc:
* @title: MyConsumer1
* @author: cao_wencao
* @date: 2019-06-04 18:02
* @version: 1.0
*
*/
@Slf4j
@Service
@RocketMQMessageListener(topic = "test-topic-1", consumerGroup = "my-consumer_test-topic-1")
public class MyConsumer1 implements RocketMQListener {
@Override
public void onMessage(String message) {
log.info("消费者消费消息开始-----------");
//JSONObject jsonObject = JSON.parseObject(message);
//OrderPaidEvent orderPaidEvent = JSONObject.parseObject(message, OrderPaidEvent.class);
log.info("消费者开始接收第一个消息received message: {}", message);
}
}
MyConsumer2
package com.thinkingcao.rocketmq.consumer;
import com.thinkingcao.rocketmq.entity.OrderPaidEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
/**
*
* @desc:
* @title: MyConsumer2
* @author: cao_wencao
* @date: 2019-06-04 18:02
* @version: 1.0
*
*/
@Slf4j
@Service
@RocketMQMessageListener(topic = "test-topic-2", consumerGroup = "my-consumer_test-topic-2")
class MyConsumer2 implements RocketMQListener {
@Override
public void onMessage(OrderPaidEvent orderPaidEvent) {
log.info("消费者开始接收第二个消息received orderPaidEvent: {}", orderPaidEvent);
log.info("消费者消费消息结束-----------");
}
}
4、新建application.properties配置文件
##消费者配置
# 端口
server.port=8888
# NameServer地址
rocketmq.name-server=127.0.0.1:9876
# 生产者组名
rocketmq.producer.group=ProducerGroup
rocketmq.producer.enable-msg-trace=true
rocketmq.producer.customized-trace-topic=my-trace-topic
5、新建消费者启动类SpringBootRocketmqConsumerApplication.java
package com.thinkingcao.rocketmq;
import com.thinkingcao.rocketmq.entity.OrderPaidEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.Resource;
/**
*
* @desc: 生产者启动类
* @auth: cao_wencao
* @date: 2019/6/4 17:40
* @param null
*
*/
@SpringBootApplication
@Slf4j
public class SpringBootRocketmqProducerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRocketmqProducerApplication.class, args);
}
}
四、测试生产者生产消息和消费者消费消息
1、生产者这时候正常生产消息
2019-06-05 20:37:13.429 INFO 24436 --- [ main] c.t.rocketmq.producer.RocketMQProducer : -----------生产者开始生产消息-----------
2019-06-05 20:37:13.983 INFO 24436 --- [ main] c.t.rocketmq.producer.RocketMQProducer : 生产者生产第一个消息完成: 主题:test-topic-1, 内容:Hello, World!
2019-06-05 20:37:14.042 INFO 24436 --- [ main] c.t.rocketmq.producer.RocketMQProducer : 生产者生产第二个消息完成: 主题:test-topic-2, 内容:OrderPaidEvent(orderId=orderId-0001, paidMoney=88)
2019-06-05 20:37:14.043 INFO 24436 --- [ main] c.t.rocketmq.producer.RocketMQProducer : -----------生产者生产消息结束-----------
2、但是有个问题出现了,消费者在消费消息的时候报了一个异常,异常如下:
2019-06-05 20:37:14.552 INFO 24024 --- [MessageThread_1] c.t.rocketmq.consumer.MyConsumer1 : 消费者消费消息开始-----------
2019-06-05 20:37:14.552 INFO 24024 --- [MessageThread_1] c.t.rocketmq.consumer.MyConsumer1 : 消费者开始接收第一个消息received message: Hello, World!
2019-06-05 20:37:14.661 INFO 24024 --- [MessageThread_1] a.r.s.s.DefaultRocketMQListenerContainer : convert failed. str:{"orderId":"orderId-0001","paidMoney":88}, msgType:class com.thinkingcao.rocketmq.entity.OrderPaidEvent
2019-06-05 20:37:14.665 WARN 24024 --- [MessageThread_1] a.r.s.s.DefaultRocketMQListenerContainer : consume message failed. messageExt:MessageExt [queueId=0, storeSize=284, queueOffset=4, sysFlag=0, bornTimestamp=1559738234040, bornHost=/192.168.86.1:61749, storeTimestamp=1559738234041, storeHost=/192.168.86.1:10911, msgId=C0A8560100002A9F00000000001E5BF0, commitLogOffset=1989616, bodyCRC=1717770219, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='test-topic-2', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=5, CONSUME_START_TIME=1559738234552, id=80b13c45-8db1-6671-8538-c4f61b48a269, UNIQ_KEY=C0A801035F7458644D46190628B80003, WAIT=false, contentType=text/plain, timestamp=1559738234038}, body=[123, 34, 111, 114, 100, 101, 114, 73, 100, 34, 58, 34, 111, 114, 100, 101, 114, 73, 100, 45, 48, 48, 48, 49, 34, 44, 34, 112, 97, 105, 100, 77, 111, 110, 101, 121, 34, 58, 56, 56, 125], transactionId='null'}]java.lang.RuntimeException: cannot convert message to class com.thinkingcao.rocketmq.entity.OrderPaidEvent
at org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer.doConvertMessage(DefaultRocketMQListenerContainer.java:382) ~[rocketmq-spring-boot-2.0.3.jar:2.0.3]
at org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer.access$100(DefaultRocketMQListenerContainer.java:57) ~[rocketmq-spring-boot-2.0.3.jar:2.0.3]
at org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer$DefaultMessageListenerConcurrently.consumeMessage(DefaultRocketMQListenerContainer.java:330) ~[rocketmq-spring-boot-2.0.3.jar:2.0.3]
at org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService$ConsumeRequest.run(ConsumeMessageConcurrentlyService.java:411) [rocketmq-client-4.5.1.jar:4.5.1]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_25]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.thinkingcao.rocketmq.entity.OrderPaidEvent` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"orderId":"orderId-0001","paidMoney":88}"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1452) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1028) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013) ~[jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004) ~[jackson-databind-2.9.8.jar:2.9.8]
at org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer.doConvertMessage(DefaultRocketMQListenerContainer.java:379) ~[rocketmq-spring-boot-2.0.3.jar:2.0.3]
... 8 common frames omitted
异常代码:
cannot convert message to class com.thinkingcao.rocketmq.entity.OrderPaidEvent
3、解决:经过很长时间的查询发现是我的实体类OrderPaidEvent没有无参的构造函数,因为序列化和反序列化需要构造函数
这时候实体OrderPaidEvent应该如下:加上一个无参的构造方法 @NoArgsConstructor,所以以后得注意了,在序列化和反序列化时,Java实体类是需要一个无参的构造方法的
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderPaidEvent implements Serializable {
private String orderId;
private Integer paidMoney;
}
再次测试时就好了,消息正常消费