一、简介
目前,市面上消息中间件产品种类繁多,譬如RabbitMq,RocektMq,Kafka,Azure EventHub, Amazon Kenesis。各种中间件的原理、机制差异很大,但归根结底都是在处理消息的发送与监听。正是基于这一根本共性,基于SpringBoot的Spring Cloud Stream对消息中间件做了一层抽象和封装,开发人员无需再关注一些通用逻辑的实现,只需要关注只需提供某个中间件的个性化配置,即可快速实现与中间交互,减少开发人员工作量,同时也降低了系统与中间件的耦合,便于中间件的切换更改。
如图,Spring Cloud Stream将中间件封装为一个Binder,将系统与某个topic的连接封装为Binding(如果系统作为Producer,则封装为一个output类型的Binding;如果系统作为消费者,则封装为一个inout类型的Binding)。无论何种中间件,配置Binding和Binder即可。
二、核心概念
目标绑定器:负责提供与外部消息传递系统集成的组件。
绑定:外部消息传递系统和应用程序提供的消息生产者和消费者之间的桥梁(由目标绑定器创建)。
消息:生产者和消费者用于与目标绑定器(以及通过外部消息传递系统的其他应用程序)进行通信的规范数据结构。
1、Binder
Binder(官网中有时也称为Destination Binder)是负责提供整合中间件所需配置的组件,实现系统与中间件连接、消息在中间件中路由、消息的数据类型转换、调用用户系统代码等,相关工作无需再由开发人员考虑。
2、Binding
Binding是负责定义系统与消息中间件交互方式的组件,如系统向那个中间件(Binder)生产或者消费消息,向该中间件的那个topic/exchange生产或消费消息,生产或者消费的确认模式如何,诸如此类的问题皆可通过Binding配置。以下以Kafka为例介绍如何配置Binder和Binding:`
在这里插入代码片
spring:
cloud:
stream:
bindings:
logger-input:
group: user-aggregator-consumer
destination: com.user.logger
binder: kafka-binder
content-type: application/json
consumer:
headerMode: raw
partitioned: true
aggregator-output:
destination: com.user.aggregator
binder: rabbit-binder
content-type: application/json
producer:
partition-key-expression: headers['partitionKey']
partitionCount: 32
kafka:
bindings:
logger-input:
consumer:
startOffset: latest
autoCommitOffset: true
autoRebalanceEnabled: true
binders:
kafka-binder:
type: kafka
environment:
spring:
cloud:
stream:
kafka:
binder:
brokers: localhost:6667
zkNodes: localhost:2181
offsetUpdateTimeWindow: 1000
autoAddPartitions: true
rabbit-binder:
type: rabbit
environment:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
首先关注binders配置,配置了两个分别名为kafka-binder和rabbit-binder的两个Binder,kafka-binder对应localhost:6667的Kafka实例,rabbit-rabbit对应localhost:5672的rabbitmq实例。通过Binders,系统便可以连接到两个消息中间价。
再关注Bindings配置,配置了两个分别名为logger-input和aggregator-outpu的两个Binding。以logger-input为例,binder: kafka-binder,表示要向kafka-binder对应的中间件发送/消费消息;destination: com.user.logger,表示要向该中间件的com.user.logger的topic发送/消费消息;consumer则指明了消费消息时一些配置。至此,系统便明确知道了向那个中间件的那个topic以何种方式发送、消费消息。
最后再关注kafka.bindings.logger-input,如果希望对Bingding做一些Spring Cloud Stream中没有涵盖的配置,可以通过type.bindings…bindingName添加个性化配置。
3、发布订阅模式
系统和中间件之间的交互遵循发布订阅模式,数据通过共享的topic向外广播。
4、消费组
Spring Cloud Stream借鉴Kafka引入了消费组的概念。出于同一消费组中的多个应用出于竞争关系,同一条消息,只会被消费组中的一个实例消费可spring.cloud.stream.bindings..group=‘consumerGroupName’声明当前应用所属的消费组。如果没有显示声明消费组,那么Spring Cloud Stream会默认为该应用创建一个不具名的、只有一个成员的消费组。
5、消费类型
Spring Cloud Stream有两种消费类型:
(1)推送模式(也称为异步模式),一旦新的消息出现,立即发送给消费者。
(2)拉取模式(也称为异步模式,消费者主动去从中间件拉取消息。如果应用希望控制消费的得速度,可采用此种方式。
6、支持分区
无论整合的中间件是否分区,如Kafa支持分区,RabbitMq则不支持分区,在Spring Cloud Stream中都能使用分区功能,它对各种分区处理实现做了抽象处理,Spring Cloud Stream将消息传递的物理媒介(Kafka的Topic、RabbitMq的Exchange)视为一种划分为多个区的结构,以此保证具有某些共同特点的消息被同一消费组消费。需要注意的是,使用分区处理,需要对同时在Producer端和Consumer端配置。
7、简单代码实现
在完成Bings配置后,需要通过代码对所配置的Bings做显示声明:
public interface EventHubProcessor {
@Input("logger-input")
SubscribableChannel inputAccount();
@Output("aggregator-outpu")
MessageChannel outputCompletedOrder();
}
除了添加依赖外,还需要在主启动类上添加@EnableBinding({Source.class, Sink.class}),如果系统只是消息对的生产者,则只需Source.class;如果只是消息的消费者,则只需Sink.class。
消费消息`
@StreamListener("inputInvoice")
public void subscribe(String payload) {
doConsumptionLogic();
}