Springcloud学习day05——Stream消息驱动

本文介绍了使用SpringCloudStream构建基于RabbitMQ的消息驱动微服务的入门案例,包括配置环境、生产者与消费者的实现、消息通道的概念以及分组消费和持久化的解决方案。通过示例展示了如何创建消息生产者和消费者,并利用Eureka进行服务注册。最后讨论了如何通过分组避免重复消费的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在B站学习的springcloud的学习记录,第5天,最难不过坚持。

配置和环境:idea2022   jdk8  mysql8.0 

本文章只用于学习和分享,欢迎大家的建议,讨论和指点。

目录

Stream消息驱动

设计思想

入门案例

分组消费和持久化


Stream消息驱动

Springcloud Stream是一个构建消息驱动的微服务框架

设计思想

  1. 生产者/消费者之间靠消息媒介传递信息内容——Message
  2. 消息必须走特定的通道——消息通道MessageChannel
  3. 消息通道里的消息如何被消费呢,谁负责收发处理——消息通道MessageChannel的子接口SubscribableChannel,由MessageHandler消息处理器所订阅

Stream就是为了让我们不再关注MQ的细节,我们只需要一种适配绑定的方式,自动的给我们在各种MQ内切换

屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程问题

通过cloud Stream中binder对象交互

Input 对应消费者,Output对应生产者。

入门案例

建model,改pom,写yml,主启动类,写业务

 

消息的生产者模块

改pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <parent>
    <artifactId>cloud2023</artifactId>
    <groupId>com.liangliang</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <modelVersion>4.0.0</modelVersion>
  <artifactId>cloud-stream-rabbitmq-provider8801</artifactId>
  <packaging>war</packaging>
  <name>cloud-stream-rabbitmq-provider8801 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>

<!--    rabbitmq-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
    </dependency>

    <!--        eureka-client 依赖jar包-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--        web-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--以上两个一定携带出现 包括了图形化、图标等-->

    <!--        一些通用配置-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>cloud-stream-rabbitmq-provider8801</finalName>
  </build>
</project>

写yml

server:
  port: 8801

spring:
  application:
    name: cloud-stream-provider
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        #表示消息的生产者
        output: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: send-8801.com  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址

主启动类

@SpringBootApplication
public class StreamMain8801 {
    public static void main(String[] args) {
        SpringApplication.run(StreamMain8801.class, args);
    }
}

业务

先创建一个接口

public interface IMessageProvider {
    public String send();
}

为接口创建一个实现类

导入Binding的Source.class的包时不要导错了,导入这个:

import org.springframework.cloud.stream.messaging.Source;

import org.springframework.cloud.stream.messaging.Source;

@EnableBinding(Source.class)  //定义消息的推送管道
public class IMessageProviderImpl implements IMessageProvider {
    @Autowired
    private MessageChannel output; //消息的发送管道

    @Override
    public String send() {
        String serial = UUID.randomUUID().toString();
        output.send(MessageBuilder.withPayload(serial).build());
        System.out.println("***serial:"+serial);
        return null;
    }
}

 然后创建一个控制类

@RestController
public class SendMessageController {
    @Autowired
    private IMessageProvider messageProvider;
    @GetMapping(value = "/sendMessage")
    public String sendMessage() {
	System.out.println("哈哈哈");
        return messageProvider.send();
    }
}

然后启动rabbitmq,再启动项目,访问localhost:15672

然后当你连续的刷新项目的访问页面后,他会出现波峰 

我们可以在后台看到

消息的接收者模块

建model,改pom,写yml

这些和8801端口的一样

除了在yml文件中将端口改成8802,和将bindings下的output修改成input,消息的接收者

server:
  port: 8803

spring:
  application:
    name: cloud-stream-consumer
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        #表示消息的接收者
        input: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置
          group: GGB

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: receive-8803.com  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址

主启动

@SpringBootApplication
public class StreamMQMain8802 {
    public static void main(String[] args) {
        SpringApplication.run(StreamMQMain8802.class,args);
    }
}

业务——控制类

@Component
@EnableBinding(Sink.class)
public class ReceviceMessageListenController {
    @Value("${server.port}")
    private String serverPort;

    @StreamListener(Sink.INPUT)
    public void input(Message<String> message){
        System.out.println("消息一号----->接收到的消息:"+message.getPayload()+"\t port:"+serverPort);
    }

}

这次使用了@StreamListener的新注解,用来监听信息,当8801有消息的时候,进入页面或者刷新页面,8802都能接受到消息。如下图可以看到。

8802的后台

8801的后台

可以看到他们的uuid是一样的相对应的

分组消费和持久化

避免重复消费的问题,当有两个接收者(两个消息接受者模块),新建一个8803,与8802model一样,端口不同,运行起来后,8801发送消息,这样的话8802和8803都会接收到消息,因为现在还没有做到分组,这样就是出现重复消息的问题,这样是不行的。

要解决这个问题,就通过分组配置group来将微服务分组。

分组的原理:微服务应用放置于同一个group中,就能够保证消息只会被其中一个应用消费一次。不同的组是可以消费的,同一个组内会发生竞争关系,只有其中一个可以消费。

不配置的话,springcloud会默认这两个微服务是不同的组

做法:自定义配置分组,自定义配置分为同一个组,解决重复消费的问题。

修改yml文件,添加代码,

在8002端口的yml文件,input下添加 group: GGA

 

然后我们重新的启动项目,我们可以在rabbit MQ中看到服务分成了两个组。

但是这样还没解决问题,我们可以通过轮询分组,将两个微服务归并到一个组中,所以端口8803的yml文件也需要改,改成和8802端口的一样。

然后再访问8801发消息,我们可以看到8802和8803的后台是轮询的方式接收消息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值