SpringCloud-消息驱动(Stream)
Stream
概述
https://spring.io/projects/spring-cloud-stream#overview
https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/
Stream解决什么问题?
当系统中使用多个不同的MQ时,使用spring cloud stream可以屏蔽 不同消息中间件的差异,统一消息的编程模型;
what
Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected with shared messaging systems.
Spring Cloud Stream 是一个消息驱动的微服务框架;
应用程序 通过inputs/outputs 与 SpringCloudStream的binder进行交互;
通过配置进行binding,SpringCloudStream的binder负责与MQ交互;
目前仅支持 RabbitMQ、Kafka;
设计思想
标准MQ

生产者与消费者 通过Message 传递内容;
Message走特定的通道MessageChannel;
Message生产者生产Message,Message订阅者消费Message;
为什么要用SpringCloudStream?
假设系统同时使用RabbitMQ、Kafka,由于这2个MQ的架构不同(比如RabbitMQ有exchange、Kafka有Topic和Partitions);

不同MQ的差异导致实际项目开发造成了困扰,比如要将一种MQ的内容迁移至另一种MQ,无疑是一场灾难;
此时MQ与系统严重耦合,而SpringCloudStream提供了一种解耦的方式;
How
在没有Binder的情况下,Spring应用要与具体的MQ进行交互,不同的MQ有差异;
通过 定义Binder作为中间层,完美实现了 应用程序与MQ 的隔离;
通过 向应用程序暴露统一的channel,使得应用程序不需要考虑不同MQ的差异;
(Input:消费者、Output:生产者)

SpringCloudStream标准流程


Binder:
连接MQ,屏蔽不同MQ的差异;
Channel:
Source/Sink:
输出:从SpringCloudStream发出消息
输入:接收消息
编码API及常用注解

How
消息生产者
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
spring:
application:
name: stream-rabbit-provider
cloud:
stream:
binders: #要绑定的RabbitMQ的服务信息
defaultRabbit: #定义的名称,用于binding整合
type: rabbit #MQ类型
environment: #RabbitMQ的相关环境配置
spring:
rabbit:
host: localhost
port: 5672
username: guest
password: guest
bindings: #服务的整合处理
output: #消息生产者
destination: studyExchange #Rabbit的Exchange名称
content-type: application/json #消息类型
binder: defaultRabbit
@EnableBinding(value = Source.class)
public class MessageSender {
@Autowired
private MessageChannel output;
public String send(){
output.send(MessageBuilder.withPayload("hhh").build());
return UUID.randomUUID().toString();
}
}
@RestController
public class MessageController {
@Autowired
private MessageSender messageSender;
@GetMapping(value = "/sendMsg")
public String send(){
return messageSender.send();
}
}
@SpringBootApplication
public class StreamRabbitProvider8801 {
public static void main(String[] args) {
SpringApplication.run(StreamRabbitProvider8801.class, args);
}
}
http://localhost:8801/sendMsg
消息消费者
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
spring:
application:
name: stream-rabbit-consumer
cloud:
stream:
binders: #要绑定的RabbitMQ的服务信息
defaultRabbit: #定义的名称,用于binding整合
type: rabbit #MQ类型
environment: #RabbitMQ的相关环境配置
spring:
rabbit:
host: localhost
port: 5672
username: guest
password: guest
bindings: #服务的整合处理
input: #消息消费者
destination: studyExchange #Rabbit的Exchange名称
content-type: application/json #消息类型
binder: defaultRabbit
@Component
@EnableBinding(value = Sink.class)
public class MessageConsumer {
@StreamListener(value = Sink.INPUT)
public void consume(Message<String> message){
System.out.println("msg: "+ message.getPayload());
}
}
@SpringBootApplication
public class StreamRabbitConsumer8802 {
public static void main(String[] args) {
SpringApplication.run(StreamRabbitConsumer8802.class, args);
}
}
分组消费/持久化
前言
当微服务是集群部署时,相同业务功能的微服务都会消费消息,存在重复消费的问题;
重复消费解决
使用SpringCloudStream的group;
(Stream中处于同一个group中的多个消费者是竞争关系,这样能保证消息只会被其中一个服务消费)

如果不显式多消费者进行分组,默认一个消费者一个组;
分组
原理:
相同业务功能的微服务可以分为一个group,这样同一个group内多个微服务是竞争关系,保证仅有一个消费者可以消费;
spring:
application:
name: stream-rabbit-consumer
cloud:
stream:
binders: #要绑定的RabbitMQ的服务信息
defaultRabbit: #定义的名称,用于binding整合
type: rabbit #MQ类型
environment: #RabbitMQ的相关环境配置
spring:
rabbit:
host: localhost
port: 5672
username: guest
password: guest
bindings: #服务的整合处理
input: #消息消费者
destination: studyExchange #Rabbit的Exchange名称
content-type: application/json #消息类型
binder: defaultRabbit
group: testGroup #消费者group
持久化
对微服务 显式指定group,应用重启后 会自动获取未消费的消息;
如果不显式指定group,由于微服务故障,将会导致消息丢失;
浙公网安备 33010602011771号