目录
Spring cloud 如何使用Spring Cloud Stream
为什么要引入Spring Cloud Stream
在实际开发过程中,服务与服务之间的数据交互,多数以消息中间件的的方式实现。由于不同消息中间件在spring cloud 中收发消息的方式存在着不同,所以编码过程中,要基于不同的消息中间件实现消息的收发。从而使得消息中间件和系统的耦合性特别高,不方便后期的扩展;
Spring Cloud Stream 能做什么
什么是Spring Cloud Stream
Spring Cloud Stream 是一个为微服务提供消息驱动能力的框架, 解决了在开发过程中可以无感知的使用消息中间件。Stream 对不同的消息中间件进一步封装,在系统中,针对不同的中间件,收发消息的方式保持一致,降低了系统和消息中间件之间的耦合性。从而有更多的精力去关注核心业务逻辑的实现;
主要概念
Spring Cloud Stream 为各种消息中间件产品提供了个性化的自动化配置实现,引入了消息分组,消息分片,发布-订阅 核心概念;
Spring Cloud Stream 抽象出了消息组件来简化微服务中消息驱动的使用,相关组件如下:
- Spring Cloud Stream的应用模型
- 绑定抽象
- 持久化发布/订阅支持
- 消费者组支持
- 分片支持(Partitioning Support)
- 可插拔API
核心模型
Spring Cloud Stream 是由一个中立的中间件内核组成,注入了输入和输出 channel ,应用和消息中间件之间的通信,就是由这些channel 完成的。而channel 则是通过Binder 与外部的消息中间件Broker 进行连接;
核心概念
Binder(绑定器)
Binder 的作用,在应用程序和消息中间件之间做了隔离,通过向应用程序暴露统一的channel ,解决了应用程序不需要在根据不同的消息中间件做具体的实现;如果更换消息中间件,只需要修改相关的Binder 即可,不需要更改业务逻辑;
Binder 提供了两个构造方法,分别是BinderConsumer、BinderProducer ,构造了消费者和生产者
Binding
Binding 用作连接应用程序和Binder, 用来生产消息和消费消息,是由Binder 创建
Group
Group 用在在集群环境下,相同消费者组内只有一个实例发生消费。如果不设置Group,Stream 默认会创建一个独立的group ,组内的实例都会发生消费。及发布-订阅模式
partition
Spring Cloud Stream支持在一个应用程序的多个实例之间数据分区,在分区的情况下,物理通信介质(例如,topic代理)被视为多分区结构。一个或多个生产者应用程序实例将数据发送给多个消费应用实例,并保证共同的特性的数据由相同的消费者实例处理。
Spring Cloud Stream提供了一个通用的抽象,用于统一方式进行分区处理,因此分区可以用于自带分区的代理(如kafka)或者不带分区的代理(如rabbiemq)
分区在有状态处理中是一个很重要的概念,其重要性体现在性能和一致性上,要确保所有相关数据被一并处理,例如,在时间窗平均计算的例子中,给定传感器测量结果应该都由同一应用实例进行计算。
借助分区的特性,我们可以实现基于Spring Cloud Stream 的有序消费;
Spring cloud 如何使用Spring Cloud Stream
环境:
spirng cloud Hoxton.SR8
spring cloud alibaba 2.2.3.Release
spring boot 2.3.2.Release
rocketMq 4.8
依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
produrce 生产者
加配置
yaml 配置文件添加stream 配置,用来指定binder,mq 地址,以及消息的topic
spring:
cloud:
stream:
rocketmq:
binder:
name-server: localhost:9876
bindings:
output:
# 用来指定mq的topic
destination: stream-test-topic
添注解
在启动类Application 添加@EnableBinding({Source.class}) 注解,Source.class 类中默认指定的outPutChanel 名为output;注意这里的channel 名称output 要和yaml 配置中bindings 属性下的channel 名称一致;否则消息无法发送出去
发消息
/**
* @Author corn
* @Date 2021/3/17 21:15
*/
@Slf4j
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
@RestController("/stream")
public class SpringCloudStreamController {
private final Source source;
/**
*@描述 默认消息发送,通过引用默认的Source类中指定的outPutChannel 名称,完成消息的发送
*@参数
*@返回值
*@创建人 corn
*@创建时间 2021/3/18
*/
@GetMapping("/sendStream")
public String SendMq(){
boolean result = this.source.output().send(MessageBuilder.withPayload("stream 消息发送").build());
log.info("消息发送:{}",result);
return "success";
}
}
Consumer 消费者
加配置
spring:
cloud:
stream:
rocketmq:
binder:
name-server: localhost:9876
bindings:
input:
# 用来指定待消费mq的topic
destination: stream-test-topic
# 定义group ,如果使用rocketmq ,必须指定group ;非rocketMq 可以不指定group,如果不指定group ,stream 会默认生成一个group,消息会被所有实例消费;在指定消费组的情况下,集群环境下,同一组内,只会有一个实例进行消息的消费
group: binder-group
添注解
在Application 启动类上添加@Enablebinding({Sink.class}), 在Sink.class 类中,默认指定了输入流inputChannel 的channel名称.这里的channel 名称要和配置文件中bindings 中要保持一致,否则无法消费到消息
消费消息
@Slf4j
@Service
public class SpringCloudStreamConsumer {
@StreamListener(Sink.INPUT)
public void receive(String messageBody){
log.info("获取到Spring Stream 请求的流消息:{}",messageBody);
}
}
总结
本文主要分析了在spring cloud 环境下,为什么要引入spring cloud stream组件、 spring cloud stream 的组成、以及基于RocketMq 实现简单的stream 消息的发送和接收;后边会对spring cloud stream 自定义注解、异常处理、事务消息、消息筛选等作详解;