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

消息生产者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<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

  

消息消费者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<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内多个微服务是竞争关系,保证仅有一个消费者可以消费;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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,由于微服务故障,将会导致消息丢失;

 

posted on   anpeiyong  阅读(234)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示