rocketmq-spring : 实战与源码解析一网打尽
RocketMQ 是大家耳熟能详的消息队列,开源项目 rocketmq-spring 可以帮助开发者在 Spring Boot 项目中快速整合 RocketMQ。
这篇文章会介绍 Spring Boot 项目使用 rocketmq-spring SDK 实现消息收发的操作流程,同时笔者会从开发者的角度解读 SDK 的设计逻辑。

1 SDK 简介

项目地址:
rocketmq-spring 的本质是一个 Spring Boot starter 。
Spring Boot 基于“约定大于配置”(Convention over configuration)这一理念来快速地开发、测试、运行和部署 Spring 应用,并能通过简单地与各种启动器(如 spring-boot-web-starter)结合,让应用直接以命令行的方式运行,不需再部署到独立容器中。
Spring Boot starter 构造的启动器使用起来非常方便,开发者只需要在 pom.xml 引入 starter 的依赖定义,在配置文件中编写约定的配置即可。
下面我们看下 rocketmq-spring-boot-starter 的配置:
1、引入依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.3</version>
</dependency>
2、约定配置

接下来,我们分别按照生产者和消费者的顺序,详细的讲解消息收发的操作过程。
2 生产者
首先我们添加依赖后,进行如下三个步骤:
1、配置文件中配置如下
rocketmq:
name-server: 127.0.0.1:9876
producer:
group: platform-sms-server-group
# access-key: myaccesskey
# secret-key: mysecretkey
topic: sms-common-topic
生产者配置非常简单,主要配置名字服务地址和生产者组。
2、需要发送消息的类中注入 RcoketMQTemplate
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Value("${rocketmq.topic}")
private String smsTopic;
3、发送消息,消息体可以是自定义对象,也可以是 Message 对象
rocketMQTemplate 类包含多钟发送消息的方法:
- 同步发送 syncSend
- 异步发送 asyncSend
- 顺序发送 syncSendOrderly
- oneway发送 sendOneWay
下面的代码展示如何同步发送消息。
String destination = StringUtils.isBlank(tags) ? topic : topic + ":" + tags;
SendResult sendResult =
rocketMQTemplate.syncSend(
destination,
MessageBuilder.withPayload(messageContent).
setHeader(MessageConst.PROPERTY_KEYS, uniqueId).
build()
);
if (sendResult != null) {
if (sendResult.getSendStatus() == SendStatus.SEND_OK) {
// send message success ,do something
}
}
syncSend 方法的第一个参数是发送的目标,格式是:topic + ":" + tags ,
第二个参数是:spring-message 规范的 message 对象 ,而 MessageBuilder 是一个工具类,方法链式调用创建消息对象。
3 消费者
1、配置文件中配置如下
rocketmq:
name-server: 127.0.0.1:9876
consumer1:
group: platform-sms-worker-common-group
topic: sms-common-topic
2、实现消息监听器
@Component
@RocketMQMessageListener(
consumerGroup = "${rocketmq.consumer1.group}", //消费组
topic = "${rocketmq.consumer1.topic}" //主题
)
public class SmsMessageCommonConsumer implements RocketMQListener<String> {
public void onMessage(String message) {
System.out.println("普通短信:" + message);
}
}
消费者实现类也可以实现 RocketMQListener<MessageExt>, 在 onMessage 方法里通过 RocketMQ 原生消息对象 MessageExt 获取更详细的消息数据 。
public void onMessage(MessageExt message) {
try {
String body = new String(message.getBody(), "UTF-8");
logger.info("普通短信:" + message);
} catch (Exception e) {
logger.error("common onMessage error:", e);
}
}
4 源码概览

最新源码中,我们可以看到源码中包含四个模块:
1、rocketmq-spring-boot-parent
该模块是父模块,定义项目所有依赖的 jar 包。
2、rocketmq-spring-boot
核心模块,实现了 starter 的核心逻辑。
3、rocketmq-spring-boot-starter
SDK 模块,简单封装,外部项目引用。
4、rocketmq-spring-boot-samples
示例代码模块。这个模块非常重要,当用户使用 SDK 时,可以参考示例快速开发。
5 starter 实现
我们重点分析下 rocketmq-spring-boot 模块的核心源码:

spring-boot-starter 实现需要包含如下三个部分:
1、定义 Spring 自身的依赖包和 RocketMQ 的依赖包 ;
2、定义spring.factories 文件
在 resources 包下创建 META-INF 目录后,新建 spring.factories 文件,并在文件中定义自动加载类,文件内容是:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration
spring boot 会根据文件中配置的自动化配置类来自动初始化相关的 Bean、Component 或 Service。
3、实现自动加载类
在 RocketMQAutoConfiguration 类的具体实现中,我们重点分析下生产者和消费者是如何分别启动的。
▍生产者发送模板类:RocketMQTemplate
RocketMQAutoConfiguration 类定义了两个默认的 Bean :


首先SpringBoot项目中配置文件中的配置值会根据属性条件绑定到 RocketMQProperties 对象 中,然后使用 RocketMQ 的原生 API 分别创建生产者 Bean 和拉取消费者 Bean , 分别将两个 bean 设置到 RocketMQTemplate 对象中。
两个重点需要强调:
发送消息时,将 spring-message 规范下的消息对象封装成 RocketMQ 消息对象

默认拉取消费者 litePullConsumer 。拉取消费者一般用于大数据批量处理场景 。

RocketMQTemplate 类封装了拉取消费者的receive方法,以方便开发者使用。

▍自定义消费者类
下图是并发消费者的例子:

那么 rocketmq-spring 是如何自动启动消费者呢 ?

spring 容器首先注册了消息监听器后置处理器,然后调用 ListenerContainerConfiguration 类的 registerContainer 方法 。
对比并发消费者的例子,我们可以看到: DefaultRocketMQListenerContainer 是对 DefaultMQPushConsumer 消费逻辑的封装。

封装消费消息的逻辑,同时满足 RocketMQListener 泛化接口支持不同参数,比如 String 、MessageExt 、自定义对象 。
首先DefaultRocketMQListenerContainer初始化之后, 获取 onMessage 方法的参数类型 。

然后消费者调用 consumeMessage 处理消息时,封装了一个 handleMessage 方法 ,将原生 RocketMQ 消息对象 MessageExt 转换成 onMessage 方法定义的参数对象,然后调用 rocketMQListener 的 onMessage 方法。

上图右侧标红的代码也就是该方法的精髓:
rocketMQListener.onMessage(doConvertMessage(messageExt));
6 写到最后
开源项目 rocketmq-spring 有很多值得学习的地方 ,我们可以从如下四个层面逐层进阶:
1、学会如何使用 :参考 rocketmq-spring-boot-samples 模块的示例代码,学会如何发送和接收消息,快速编码;
2、模块设计:学习项目的模块分层 (父模块、SDK 模块、核心实现模块、示例代码模块);
3、starter 设计思路 :定义自动配置文件 spring.factories 、设计配置属性类 、在 RocketMQ client 的基础上实现优雅的封装、深入理解 RocketMQ 源码等;
4、举一反三:当我们理解了 rocketmq-spring 的源码,我们可以尝试模仿该项目写一个简单的 spring boot starter。
如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!
rocketmq-spring : 实战与源码解析一网打尽的更多相关文章
- 【Java实战】源码解析Java SPI(Service Provider Interface )机制原理
一.背景知识 在阅读开源框架源码时,发现许多框架都支持SPI(Service Provider Interface ),前面有篇文章JDBC对Driver的加载时应用了SPI,参考[Hibernate ...
- Java生鲜电商平台-电商中海量搜索ElasticSearch架构设计实战与源码解析
Java生鲜电商平台-电商中海量搜索ElasticSearch架构设计实战与源码解析 生鲜电商搜索引擎的特点 众所周知,标准的搜索引擎主要分成三个大的部分,第一步是爬虫系统,第二步是数据分析,第三步才 ...
- Spring Security 解析(七) —— Spring Security Oauth2 源码解析
Spring Security 解析(七) -- Spring Security Oauth2 源码解析 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因 ...
- spring boot @Value源码解析
Spring boot 的@Value只能用于bean中,在bean的实例化时,会给@Value的属性赋值:如下面的例子: @SpringBootApplication @Slf4j public c ...
- Feign 系列(05)Spring Cloud OpenFeign 源码解析
Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/ ...
- 异步任务spring @Async注解源码解析
1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就 ...
- Spring Security 访问控制 源码解析
上篇 Spring Security 登录校验 源码解析 分析了使用Spring Security时用户登录时验证并返回token过程,本篇分析下用户带token访问时,如何验证用户登录状态及权限问 ...
- Spring @Import注解源码解析
简介 Spring 3.0之前,创建Bean可以通过xml配置文件与扫描特定包下面的类来将类注入到Spring IOC容器内.而在Spring 3.0之后提供了JavaConfig的方式,也就是将IO ...
- spring boot整合spring5-webflux从0开始的实战及源码解析
上篇文章<你的响应阻塞了没有?--Spring-WebFlux源码分析>介绍了spring5.0 新出来的异步非阻塞服务,很多读者说太理论了,太单调了,这次我们就通过一个从0开始的实例实战 ...
- AndFix热修复 —— 实战与源码解析
当你的应用发布后第二天却发现一个重要的bug要修复,头疼的同时你可能想着赶紧修复重新打个包发布出去,让用户收到自动更新重新下载.但是万事皆有可能,万一隔一天又发现一个急需修复的bug呢?难道再次发布打 ...
随机推荐
- fpga 通过vga模块使电脑显示图片
对vga模块搞了好几天,vga接口时序不难,就是行计数,列计数,对应到每一个像素上去.这里我先把vga控制模块的程序付上.采用的是小梅哥的程序.屏幕是800X600,配置的时钟是40M.注意改变屏幕尺 ...
- C++/Lua栈操作
一.Lua栈结构 1. index为正数 c++获取lua的数组元素的实例: // 接口参数:void lua_rawgeti (lua_State *L, int index, int n); lu ...
- LoadRunner性能测试-app压力测试
步骤分为三步: 一,录制脚本 录制脚本原理:启动LR代理服务器监听设置好的端口号是否有请求发送给服务器,有请求时,代理服务器接收请求,并转发给对应的系统服务器,LR从而获取到请求的信息与数据,生成脚本 ...
- spring-boot项目布到tomcat容器下部署
一.修改打包形式 在pom.xml里设置 `war` <packaging>war</packaging> 二.移除嵌入式tomcat插件 在pom.xml里找到spring- ...
- PHP程序的“Missing argument 3”的错误提示解决方法
是在定义函数时为三个参数,但实际调用时只调了两个参数 解决办法: 一种:在调用函数地方补全调用的参数 二种:修改函数传入参数值,设置带有默认值, Missing argument 3 fo ...
- samba缓存问题
samba 在第一次登录时,会在windows上缓存着登录密码,当你重新修改samba服务端的密码, 再次登录时,windows会自动用缓存的旧密码登录,导致的登录失败.
- C语言中~与!的区别
! 是逻辑非or否定 凡是a的值不为0的,!a 就等于0: 如果a的值为0,则 !a 的值为1 而~这个是 按位取反 比如 int a=2 ; 用二进制表示为00 00 00 10; 则 !a ...
- Vue父子组件传值.sync
<template> <div class="content"> <btn :btnName.sync='num' ></btn> ...
- tableau连接mysql
1.下载驱动地址:https://dev.mysql.com/downloads/connector/odbc/ 2.选择MSI Installer自动安装自动配置 3.本地127.0.0.1(其他I ...
- C#开发微信
C#开发微信门户及应用教程 C#开发微信门户及应用(1)--开始使用微信接口... 6 1.微信账号... 6 2.微信菜单定义... 7 3.接入微信的链接处理... 8 4.使用开发方式创建菜 ...