(九)Spring Cloud Alibaba RocketMQ(含案例源码、案例解析及软件)

案例源码gitee地址:

https://gitee.com/BanSheng/spring-cloud-alibaba-examples/tree/master/spring-cloud-bus-rocketmq-example

Spring Cloud Alibaba RocketMQ

一、RocketMQ 介绍

RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。

具有以下特点:

  • 能够保证严格的消息顺序
  • 提供丰富的消息拉取模式
  • 高效的订阅者水平扩展能力
  • 实时的消息订阅机制
  • 亿级消息堆积能力

二、RocketMQ 基本使用

2.1 下载 RocketMQ

使用浏览器打开:

http://rocketmq.apache.org/release_notes/release-notes-4.4.0/

这里我们选择 4.4.0 版本的原因在于,我们 spring cloud alibaba 版本为:2.2.0.RELEASE,

它里面控制的 rocketMQ 的版是 4.4.0。

直接下载的速度太慢,大家可以从百度云网盘下载该文件。

链接:https://pan.baidu.com/s/1o4HAuRQIiEQzMEJCD9YX0Q  提取码:18x3 

2.2 RocketMQ 目录分析

将该压缩包复制到软件目录里面,使用压缩软件进行解压。

Benchmark:包含一些性能测试的脚本;

Bin:可执行文件目录;

Conf:配置文件目录;

Lib:第三方依赖;

LICENSE:授权信息;

NOTICE:版本公告;

2.3  配置环境变量

找到配置环境变量的对话框:

点击新建创建一个环境变量:

  • 变量名:ROCKETMQ_HOME
  • 变量值:D:\devtools\rocketMQ\rocketmq-all-4.4.0-bin-release

2.4 RocketMQ 的启动

我们进入到${rocketMQ}/bin,在此目录里面启动和停止命令。

2.4.1 启动 NameServer

注意:弹出的黑窗口不要关闭。

2.4.2 启动 Broker

./mqbroker.cmd -nlocalhost:9876

其中:

-n localhost:9876 是为了指定nameserver 的地址

2.5 RocketMQ 的停止

直接把弹出的黑框关闭,即可停止 RocketMQ 的 namesrv 和 broker。

2.6 RocketMQ  控制台的安装

Rocketmq 控制台可以可视化 MQ的消息发送!

2.6.1 下载 RocketMQ 控制台

直接从官网下载的是源码,比较麻烦,我提供了可以运行的 jar,大家可以直接下载

链接:https://pan.baidu.com/s/1BWokojTSl6n8nxHL0mvTww  提取码:nhnj

2.6.2 复制到软件目录里面

2.6.3 运行该 jar

java -jar rocketmq-console-ng-1.0.0.jar --rocketmq.config.namesrvAddr=127.0.0.1:9876

其中:

--rocketmq.config.namesrvAddr=127.0.0.1:9876 是为了指定 nameserver 的地址

运行成功后:

访问:

http://localhost:8080/#/

三、Spring Cloud Stream 介绍

Spring Cloud Stream是一个用于构建基于消息的微服务应用框架。它基于 SpringBoot来创建具有生产级别的单机 Spring 应用,并且使用 Spring Integration 与 Broker 进行连接。

Spring Cloud Stream 提供了消息中间件配置的统一抽象,推出了 publish-subscribe、consumer groups、partition 这些统一的概念。

Spring Cloud Stream 内部有两个概念:Binder 和Binding:

  •  Binder: 跟外部消息中间件集成的组件,用来创建 Binding,各消息中间件都有自己的Binder 实现。

举例说明:

Kafka 的实现 KafkaMessageChannelBinder,RabbitMQ 的实现 RabbitMessageChannelBinder以及 RocketMQ 的实现 RocketMQMessageChannelBinder。

  •  Binding: 包括 Input Binding 和 Output Binding。

Binding 在消息中间件与应用程序提供的 Provider 和 Consumer 之间提供了一个桥梁,实现了开发者只需使用应用程序的 Provider 或 Consumer 生产或消费数据即可,屏蔽了开发者与底层消息中间件的接触。


四、测试框架搭建

我们将创建 spring-cloud-bus-rocketmq-example 项目,用来测试它的所有功能。

4.1  搭建 spring-cloud-bus-rocketmq-example

spring-cloud-bus-rocketmq-example 将去除子模块的公共依赖部分。

4.1.1 使用 IDEA 创建一个 Maven 项目

选择 Maven 项目:

点击 Next ,填写以下的内容:

Parent:我们选择 spring-cloud-alibaba-examples

Name:spring-cloud-bus-rocketmq-example

其他的项保持不变。

点击 Finish 完成创建。

4.1.2 添加依赖

打开项目的 pom.xml 文件,我们添加以下的内容:

<dependencies>
	<dependency>
		<groupId>com.alibaba.cloud</groupId>
		<artifactId>spring-cloud-starter-bus-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>

4.1.3 完整的 pom.xml 文件

<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
		<artifactId>spring-cloud-alibaba-examples</artifactId>
		<groupId>com.bjsxt</groupId>
		<version>1.0</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>
	<artifactId>spring-cloud-bus-rocketmq-example</artifactId>
	<packaging>pom</packaging>
	<modules>
		<module>rocketmq-produce-example</module>
	</modules>
	<dependencies>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-bus-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>

4.2  搭建 rocketmq-produce-example

produce 代表服务的生产者,用来发送消息。

4.2.1 使用 IDEA 创建一个 Maven 项目

选择 Maven:

点击 Next 添加以下的内容:

Parent:spring-cloud-bus-rocketmq-example

Name:rocketmq-produce-example

点击 Finish 完成项目的创建

4.2.2 修改 Maven 的打包方式

此项目我们以后可能需要使用 jar 发布,在此,我们添加 spring-boot 的打包插件:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

4.2.3 完整的 pom.xml 文件如下

<?xmlversion="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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
		<artifactId>spring-cloud-bus-rocketmq-example</artifactId>
		<groupId>com.bjsxt</groupId>
		<version>1.0</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>
	<artifactId>rocketmq-produce-example</artifactId>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

4.3  搭建 rocketmq-produce-example

4.3.1 使用 IDEA 创建一个 Maven 项目

选择 Maven:

点击 Next 添加以下的内容:

Parent:spring-cloud-bus-rocketmq-example

Name:rocketmq-consumer-example

点击 Finish 完成项目的创建

4.3.2 修改 Maven 的打包方式

为了以后打包为一个 jar 发布,我们添加一个打包插件:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

4.3.3 完整的 pom.xml 文件

<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
		<artifactId>spring-cloud-bus-rocketmq-example</artifactId>
		<groupId>com.bjsxt</groupId>
		<version>1.0</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>
	<artifactId>rocketmq-consume-example</artifactId>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

4.4  项目的完整结构如下

五、完善 rocketmq-produce-example 项目

 

5.1  添加一个配置文件

配置信息如下:

logging.level.com.alibaba.cloud.stream.binder.rocketmq=DEBUG
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
spring.cloud.stream.bindings.output1.destination=test-topic
spring.cloud.stream.bindings.output1.content-type=application/json
spring.cloud.stream.rocketmq.bindings.output1.producer.group=binder-group
spring.cloud.stream.rocketmq.bindings.output1.producer.sync=true
spring.cloud.stream.bindings.output2.destination=TransactionTopic
spring.cloud.stream.bindings.output2.content-type=application/json
spring.cloud.stream.rocketmq.bindings.output2.producer.transactional=true
spring.cloud.stream.rocketmq.bindings.output2.producer.group=myTxProducerGroup
spring.cloud.stream.bindings.output3.destination=pull-topic
spring.cloud.stream.bindings.output3.content-type=text/plain
spring.cloud.stream.rocketmq.bindings.output3.producer.group=pull-binder-group
spring.application.name=rocketmq-produce-example
server.port=28081
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

5.2  添加一个启动类

@SpringBootApplication
public classRocketMQProduceApplication {
	public static void main(String[] args) {
		SpringApplication.run(RocketMQProduceApplication.class, args);
	}
}

5.3  添加 MQSource

在 Source 里面定义输出:

public interface MQSource{
	@Output("output1")
	MessageChannel output1() ;
	@Output("output2")
	MessageChannel output2() ;
	@Output("output1")
	MessageChannel output3() ;
}

5.4  添加配置类

代码如下:

@Configuration
@EnableBinding({MQSource.class})
public class MQConfig {
}

5.5  添加发送消息的类

@Service
public class SendService {
	@Autowired
	private MQSource source;
	/**
	* 发送简单的测试消息
	*@param msg
	*@throws Exception
	*/
	public void send(String msg) throws Exception {
		source.output1().send(MessageBuilder.withPayload(msg).build());
	}
	/**
	* 发消息时添加标签
	*@param msg
	*@param tag
	*@param <T>
	*@throws Exception
	*/
	public <T> voidsendWithTags(T msg, String tag) throws Exception {
		Messagemessage = MessageBuilder.createMessage(msg,
		newMessageHeaders(Stream.of(tag).collect(Collectors
		.toMap(str -> MessageConst.PROPERTY_TAGS,
		String::toString))));
		source.output1().send(message);
	}
	/**
	* 发送一个对象消息
	*@param msg
	*@param tag
	*@param <T>
	*@throws Exception
	*/
	public <T> voidsendObject(T msg, String tag) throws Exception {
		Messagemessage = MessageBuilder.withPayload(msg)
		.setHeader(MessageConst.PROPERTY_TAGS, tag)
		.setHeader(MessageHeaders.CONTENT_TYPE,
		MimeTypeUtils.APPLICATION_JSON)
		.build();
		source.output1().send(message);
	}
	/**
	* 发送事务的消息
	*@param msg
	*@param num
	*@param <T>
	*@throws Exception
	*/
	public <T> voidsendTransactionalMsg(T msg, int num) throws Exception {
		MessageBuilder builder = MessageBuilder.withPayload(msg)
		.setHeader(MessageHeaders.CONTENT_TYPE,
		MimeTypeUtils.APPLICATION_JSON);
		builder.setHeader("test", String.valueOf(num));
		Messagemessage = builder.build();
		source.output2().send(message);
	}
	public void sendMassiveMessage(String msg) {
		source.output3().send(MessageBuilder.withPayload(msg).build());
	}
}

5.6  事务消息往往需要我们监听回查

新建一个类:

代码如下:

/**
* TransactionStatus.CommitTransaction :消息提交,当消息状态为 CommitTransaction ,表示允许消费者允许消费当前消息
* TransactionStatus.RollbackTransaction :消息回滚,表示 MQ 服务端将会删除当前半消息,不允许消费者消费。
* TransactionStatus.Unknown :中间状态,表示 MQ 服务需要发起回查操作,检测当前发送方本地事务的执行状态。
*/
@RocketMQTransactionListener(txProducerGroup = "myTxProducerGroup",corePoolSize = 5,maximumPoolSize = 10)
public class TransactionListenerImplimplements RocketMQLocalTransactionListener {
	/**
	* 消息生产者需要在 executeLocalTransaction 中执行本地事务 , 当事务半消息提交成功,执行完毕后需要返回事务状态码。
	* @param msg
	* @param o
	* @return
	*/
	@Override
	public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object o)
	{
		Object num = msg.getHeaders().get("test");
		if ("1".equals(num)) {
			System.out.println("executer: " + new String((byte[]) msg.getPayload()) + " unknown");
			return RocketMQLocalTransactionState.UNKNOWN; // 将会导致再次查询本地事务
		}
		else if ("2".equals(num)) {
			System.out.println("executer: " + new String((byte[]) msg.getPayload()) + " rollback");
			return RocketMQLocalTransactionState.ROLLBACK; // 半消息将会被 mq 服务器删除,并且消费者不会消费到该消息
		}
		System.out.println("executer: " + new String((byte[]) msg.getPayload()) + "commit");
		return RocketMQLocalTransactionState.COMMIT; // 半消息提交,消费者会消费到该消息。
	}
	/**
	* 实现 checkLocalTransaction 方法,该方法用于进行本地事务执行情况回查,并回应事务状态给MQ 的 broker,
	* 执行完成之后需要返回对应的事务状态码
	* @param message
	* @return
	*/
	@Override
	public RocketMQLocalTransactionStatecheckLocalTransaction(Message message) {
		System.out.println("check: " + new String((byte[]) message.getPayload()));
		return RocketMQLocalTransactionState.COMMIT;
	}
}

5.7  构建一个简单的模型

代码如下:

5.8  测试消息的发送

 

5.9  启动类

代码如下:

@SpringBootApplication
public class RocketMQProduceApplication {
	public static void main(String[] args) {
		SpringApplication.run(RocketMQProduceApplication.class, args);
	}
}

六、完善 rocketmq-consumer-example 项目

6.1  添加配置文件

内容如下:

spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
spring.cloud.stream.bindings.input1.destination=test-topic
spring.cloud.stream.bindings.input1.content-type=text/plain
spring.cloud.stream.bindings.input1.group=test-group1
spring.cloud.stream.rocketmq.bindings.input1.consumer.orderly=true
spring.cloud.stream.bindings.input2.destination=test-topic
spring.cloud.stream.bindings.input2.content-type=text/plain
spring.cloud.stream.bindings.input2.group=test-group2
spring.cloud.stream.rocketmq.bindings.input2.consumer.orderly=false
spring.cloud.stream.rocketmq.bindings.input2.consumer.tags=tagStr
spring.cloud.stream.bindings.input2.consumer.concurrency=20
spring.cloud.stream.bindings.input2.consumer.maxAttempts=1
spring.cloud.stream.bindings.input3.destination=test-topic
spring.cloud.stream.bindings.input3.content-type=application/json
spring.cloud.stream.bindings.input3.group=test-group3
spring.cloud.stream.rocketmq.bindings.input3.consumer.tags=tagObj
spring.cloud.stream.bindings.input3.consumer.concurrency=20
spring.cloud.stream.bindings.input4.destination=TransactionTopic
spring.cloud.stream.bindings.input4.content-type=text/plain
spring.cloud.stream.bindings.input4.group=transaction-group
spring.cloud.stream.bindings.input4.consumer.concurrency=5
spring.cloud.stream.bindings.input5.destination=pull-topic
spring.cloud.stream.bindings.input5.content-type=text/plain
spring.cloud.stream.bindings.input5.group=pull-topic-group
spring.application.name=rocketmq-consume-example
server.port=28082
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

6.2  添加一个 Sink

在 Sink 里面添加输入:

public interface Sink {
	@Input("input1")
	SubscribableChannel input1();
	@Input("input2")
	SubscribableChannel input2();
	@Input("input3")
	SubscribableChannel input3();
	@Input("input4")
	SubscribableChannel input4();
	@Input("input5")
	PollableMessageSource input5();
}

6.3  创建消息的监听器

/**
* receive
*/
@Service
public class ReceiveService {
	@StreamListener("input1")
	public void receiveInput1(String receiveMsg) {
		System.out.println("input1 receive: " + receiveMsg);
	}
	@StreamListener("input2")
	public void receiveInput2(String receiveMsg) {
		System.out.println("input2 receive: " + receiveMsg);
	}
	@StreamListener("input3")
	public void receiveInput3(@Payload User user) {
		System.out.println("input3 receive: " + user);
	}
	@StreamListener("input4")
	public void receiveTransactionalMsg(String transactionMsg) {
		System.out.println("input4 receive transaction msg: " + transactionMsg);
	}
}

6.4  主动去 mq  服务器拉起消息

使用定时任务,主动去服务器拉取消息:

@Service
public class PullMessageTask {
	@Autowired
	private Sink sink ;
	@Scheduled(fixedRate = 5*1000)
	public void pullMessage(){
		sink.input5().poll((message) -> {
			String payload = (String) message.getPayload();
			System.out.println("pull msg: " + payload);
		}, new ParameterizedTypeReference<String>() {
		});
	}
}

6.5  模型类

直接从 produce 里面复制过来:


 

6.6  配置类

新建 MQConfig:

代码如下:

@Configuration
@EnableBinding({Sink.class})
public classMQConfig {
}

6.7  启动类

@SpringBootApplication
@EnableScheduling
public classRocketMQConsumerApplication {
	public static void main(String[] args) {
		SpringApplication.run(RocketMQConsumerApplication.class ,args) ;
	}
}


七、测试案例测试

7.1  启动服务

启动 2 个服务:

  • rocketmq-produce-example
  • rocketmq-consumer-example

7.2  发送消息测试

7.2.1 发送简单的字符串

http://localhost:28081/send/simple?msg=RocketMQ

7.2.2 发送带标签的消息

7.2.3 发送对象消息

http://localhost:28081/send/object?id=1&userName=bjsxt&password=123456&tags=xxx

7.2.4 发送事务消息

http://localhost:28081/send/transaction?msg=order&num=1

http://localhost:28081/send/transaction?msg=order&num=2

http://localhost:28081/send/transaction?msg=order&num=3

7.2.5 手动拉取消息

http://localhost:28081/send/poll?msg=order

案例源码gitee地址:https://gitee.com/BanSheng/spring-cloud-alibaba-examples/tree/master/spring-cloud-bus-rocketmq-example

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

plenilune-望月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值