SpringCloud Stream消息驱动
1、概述
1.1、是什么
官方定义 Spring Cloud Stream 是一个构建消息驱动微服务的框架。
应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream中binder对象交互。
通过我们配置来binding(绑定) ,而 Spring Cloud Stream 的 binder对象负责与消息中间件交互。所以,我们只需要搞清楚如何与 Spring Cloud Stream 交互就可以方便使用消息驱动的方式。
通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。
Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,引用了发布-订阅、消费组、分区的三个核心概念。
目前仅支持RabbitMQ、Kafka。
Spring官网:https://spring.io/projects/spring-cloud-stream#overview
Stream中文手册:https://m.wang1314.com/doc/webapp/topic/20971999.html
1.2、设计思想
通过定义绑定器Binder作为中间层,实现了应用程序与消息中间件细节之间的隔离。
Binder可以生成Binding,Binding用来绑定消息容器的生产者和消费者,它有两种类型,INPUT和OUTPUT,INPUT对应于消费者,OUTPUT对应于生产者。
Stream中的消息通信方式遵循了发布-订阅模式,Topic主题进行广播,在RabbitMQ就是Exchange,在Kakfa中就是Topic。
1.3、标准流程套路
Binder:很方便的连接中间件,屏蔽差异。
Channel:通道,是队列Queue的一种抽象,在消息通讯系统中就是实现存储和转发的媒介,通过Channel对队列进行配置。
Source和Sink:简单的可理解为参照对象是Spring Cloud Stream自身,
从Stream发布消息就是输出,接受消息就是输入。
常用API和注解
2、构建
2.1、消息驱动的生产者
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
配置文件
spring:
application:
name: cloud-stream-provider
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
output: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
主运行类
@SpringBootApplication
@EnableEurekaClient
public class StreamMQMain8801
{
public static void main(String[] args)
{
SpringApplication.run(StreamMQMain8801.class,args);
}
}
发送消息的接口
public interface IMessageProvider
{
public String send() ;
}
实现类
@EnableBinding(Source.class)
public class IMessageProviderImpl implements IMessageProvider {
@Resource
private MessageChannel output;
@Override
public String sendMessage() {
String serial = UUID.randomUUID().toString();
boolean send = output.send(MessageBuilder.withPayload(serial).build());
System.out.println("******serial******: " + serial);
if (send) {
return "发送成功:"+serial;
} else {
return "发送失败:"+serial;
}
}
}
Controller控制层
@RestController
public class SendMessageController
{
@Resource
private IMessageProvider messageProvider;
@GetMapping(value = "/sendMessage")
public String sendMessage()
{
return messageProvider.send();
}
}
访问:http://localhost:8801/sendMessage可以发送消息,在RabbitMQ上面看见明显的消息波动峰
2.2、消息驱动的消费者
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
配置文件
spring:
application:
name: cloud-stream-consumer
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
input: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置
主运行类
@SpringBootApplication
@EnableEurekaClient
public class StreamMQMain8802
{
public static void main(String[] args)
{
SpringApplication.run(StreamMQMain8802.class,args);
}
}
Controller控制层
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListener {
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT)
public void input(Message<String> message) {
System.out.println("所接收到的消息为======" + message.getPayload() + "\t " + "端口号" + serverPort);
}
}
使用:http://localhost:8801/sendMessage发送信息,在8802端口可以接收到消息,避免了中间件的不同,类似于一个Template可以进行发送和接收消息。
3、Stream的分组消费与持久化
3.1、分组消费
再次构建一个8803端口与8802类似,步骤省略
可以发现,如果生产者发送一条消息,两个消费者会同时消费一条消息,因为他们会自动生成一个流水号将他们划分到不同组,所以这里我们需要使用配置方法将其配置到同一个组去避免重复消费。
yml配置文件
spring:
cloud:
stream:
bindings:
input:
group: 组名
这样就将其创建到同一个组去,再次发送消息,一条消息只会被一个消费端消费,不会重复消费
3.2、持久化
Stream默认开启持久化,即使消费端宕机了,之后生产者发送消息的时候服务端收不到,当消费端再次上线且组别没有发生变化的时候消费端还能消费到未消费的信息。这样自动实现了持久化。
4、学习地址
来源:哔哩哔哩尚硅谷:https://www.bilibili.com/video/BV18E411x7eT