Stream
概述
1、Spring Cloud Stream 用于构建高度可扩展的事件驱动的微服务,并与共享消息系统相连
2、屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型
(1)构建、测试、部署以数据为中心的应用程序
(2)应用现代微服务架构模式,包括通过消息传递进行组合
(3)用以事件为中心的思维来解耦应用程序的责任。一个事件可以代表在时间上发生的事情,下游的消费者应用程序可以对其作出反应,而不知道它的来源或生产者的身份
(4)将业务逻辑移植到消息代理上(如:RabbitMQ、Apache Kafka、Amazon Kinesis)
(5)依靠框架的自动内容类型支持来处理常见的使用情况,扩展到不同的数据转换类型是可能的
设计思想
1、统一底层差异
(1)在没有绑定器这个概念的情况下,SpringBoot 应用要直接与消息中间件进行信息交互时,由于各消息中间件构建的初衷不同,它们的实现细节上会有较大的差异性
(2)通过定义绑定器作为中间层,完美地实现应用程序与消息中间件细节之间的隔离
(3)通过向应用程序暴露统一的 Channel,使得应用程序不需要再考虑各种不同的消息中间件实现
(4)Stream 对消息中间件的进一步封装,可以做到代码层面对中间件的无感知,甚至于动态的切换中间件,使得微服务开发的高度解耦,服务可以更多地关注自己的业务流程
2、Binder
(1)通过定义 Binder(绑定器)作为中间层,实现应用程序与消息中间件细节之间的隔离
(2)Binder 可以生成 Binding,Binding 用来绑定消息容器的生产者和消费者
(3)Binding 两种类型:INPUT 对应消费者,OUTPUT 对应生产者
3、Stream 消息通信方式遵循发布-订阅模式
(1)RabbitMQ:Exchange
(2)Kafka:Topic
Stream
1、结构
(1)Binder:连接中间件,屏蔽差异
(2)Channel:Queue 的抽象,存储、转发消息,通过 Channel 配置队列
(3)Source:输出、发布消息
(4)Sink:输入、接收消息
2、模型
(1)Middleware:消息中间件,只支持 RabbitMQ、Kafka
(2)Binder:应用与消息中间件之间的封装,连接中间件
3、注解
(1)@Input:输入通道,接收消息进入应用程序
(2)@Output:输出通道,发布消息离开应用程序
(3)@StreamListener:监听队列,用于消费者队列接收消息
(4)@EnableBinding:绑定 Channel、Exchange
消息驱动的生产者
1、核心依赖(以 RabbitMQ 为例)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
2、yaml 配置
server:
port: 8801
spring:
application:
name: cloud-stream-provider
cloud:
stream:
# 配置绑定的RabbitMQ服务信息
binders:
# 表示定义的名称,用于binding整合
defaultRabbit:
# 消息组件类型
type: rabbit
# 设置RabbitMQ相关的环境配置
environment:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# 服务的整合处理
bindings:
# 通道的名称
output:
# 所使用的Exchange名称定义
destination: TestExchange
# 设置消息类型,文本则设置为 text/plain
content-type: application/json
# 设置要绑定的消息服务的具体设置
binder: defaultRabbit
#省略注册配置
3、业务类
(1)发送消息接口
public interface MessageProvider {
public String send() ;
}
(2)发送消息实现类
//理解为定义一个发送消息管道
@EnableBinding(Source.class)
public class MessageProviderImpl implements MessageProvider {
//消息的发送管道
@Resource
private MessageChannel output;
@Override
public String send() {
String serial = UUID.randomUUID().toString();
//创建并发送消息
//MessageBuilder
this.output.send(MessageBuilder.withPayload(serial).build());
return serial;
}
}
(3)Controller
@RestController
public class SendMessageController {
@Resource
private MessageProvider messageProvider;
@GetMapping(value = "/sendMessage")
public String sendMessage() {
return messageProvider.send();
}
}
消息驱动的消费者
1、核心依赖(以 RabbitMQ 为例)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
2、yaml 配置
server:
port: 8802
spring:
application:
name: cloud-stream-consumer
cloud:
stream:
# 配置绑定的RabbitMQ服务信息
binders:
# 表示定义的名称,用于binding整合
defaultRabbit:
# 消息组件类型
type: rabbit
# 设置RabbitMQ相关的环境配置
environment:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# 服务的整合处理
bindings:
# 通道的名称
input:
# 所使用的Exchange名称定义
destination: TestExchange
# 设置消息类型,文本则设置为 text/plain
content-type: application/json
# 设置要绑定的消息服务的具体设置
binder: defaultRabbit
#省略注册配置
3、业务类
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListener {
@StreamListener(Sink.INPUT)
public void input(Message<String> message) {
System.out.println(message.getPayload());
}
}
消息分组
1、yaml 配置
spring:
cloud:
stream:
# 服务的整合处理
bindings:
# 通道的名称
input:
group: ConsumerGroup1
2、解决:重复消费
(1)在 Stream 中,处于同一个 group 中的多个消费者是竞争关系,能够保证消息只会被其中一个应用消费一次
(2)不同组是可以全面消费(重复消费)
(3)同一组内会发生竞争关系,只有其中一个可以消费
3、解决:消息丢失
(1)无分组:应用重启后,不会获取停机时段的消息
(2)有分组:应用重启后,自动消费停机时段的消息,实现消息持久化
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战