SpringCloud消息组件: Stream 和 Bus


提示:以下是本篇文章正文内容,SpringCloud 系列学习将会持续更新

在这里插入图片描述

SpringCloud 消息组件

前面我们已经学习了如何使用 RabbitMQ 消息队列,接着我们来简单介绍一下 SpringCloud 为我们提供的一些消息组件。

  • SpringCloud Stream它是通过对消息中间件进行抽象封装,提供一个统一的接口供我们发送和监听消息。
    主要功能:实现消息队列的相关操作,消息的异步调用能让各个服务充分解耦且更加灵活。
  • SpringCloud Bus它是在 Stream 基础之上再次进行抽象封装,使得我们可以在不用理解消息发送、监听等概念的基础上使用消息来完成业务逻辑的处理。
    主要功能:借助消息驱动来实现将消息(事件)广播到各个服务中,让服务对这些消息进行消费。

一、SpringCloud Stream

官方文档https://docs.spring.io/spring-cloud-stream/docs/3.2.2/reference/html

前面我们介绍了 RabbitMQ,了解了消息队列相关的一些操作,但是可能我们会遇到不同的系统在用不同的消息队列,比如系统A 用的 Kafka、系统B 用的 RabbitMQ,但是我们现在又没有学习过 Kafka,那么怎么办呢?有没有一种方式像 JDBC 一样,我们只需要关心 SQL 和业务本身,而不用关心数据库的具体实现呢?

SpringCloud Stream 能够做到,它能够屏蔽底层实现,我们使用统一的消息队列操作方式就能操作多种不同类型的消息队列。
在这里插入图片描述
它屏蔽了 RabbitMQ 底层操作,让我们使用统一的 InputOutput 形式,以 Binder 为中间件,这样就算我们切换了不同的消息队列,也无需修改代码,而具体某种消息队列的底层实现是交给 Stream 在做的。

这里我们创建一个新的项目来测试一下:
在这里插入图片描述

1.1 添加依赖

父工程作 SpringCloud 的版本管理:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2021.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

两个子项目添加 stream-rabbit 依赖:

<dependencies>
    <!--  RabbitMQ的Stream实现  -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

回到目录…

1.2 生产者

application.yml 配置文件

server:
  port: 8080
spring:
  cloud:
    stream:
      binders:   #此处配置要绑定的rabbitmq的服务信息
        rabbit-server: #绑定名称,随便起一个就行
          type: rabbit #消息组件类型,这里使用的是RabbitMQ,就填写rabbit
          environment:  #服务器相关信息,按照下面的方式填写就行,爆红别管
            spring:
              rabbitmq:
                host: 1.15.76.95
                port: 5672
                username: admin
                password: 123456
                virtual-host: /test
      bindings:
        test-out-0: #生产者是输出,默认名称为 方法名-out-index
          destination: test.exchange # 指定交换机,没有会自动创建

发送消息StreamBridge.send(String bindingName, Object data)

@RestController
public class PublishController {
    
    

    @Resource
    StreamBridge bridge;  //通过bridge来发送消息

    @RequestMapping("/publish")
    public String publish(){
    
    
        //第一个参数是交换机名称,对应的不是在rabbitMQ中的名称,而是对于我们生产者来说的名称:<名称>-out-<index>
        //这里我们使用输出的方式,来将数据发送到消息队列,注意这里的名称会和之后的消费者Bean名称进行对应
        bridge.send("test-out-0", "HelloWorld!");
        return "消息发送成功!";
    }
}

③现在我们来将生产者启动一下,访问一下接口:
在这里插入图片描述

消息发送成功,我们来看看 RabbitMQ:新增了一个 test.exchange 交换机,是 topic 类型的。
在这里插入图片描述

但是目前还没有生成队列,所以此交换机没有绑定任何队列,我们刚刚发送的消息也就发丢了。
在这里插入图片描述

回到目录…

1.3 消费者

application.yml 配置文件

server:
  port: 8081
spring:
  cloud:
    stream:
      binders:
        rabbit-server:
          type: rabbit
          environment:
            spring:
              rabbitmq:
                host: 1.15.76.95
                port: 5672
                username: admin
                password: 123456
                virtual-host: /test
      bindings:
        test-in-0: #其余配置不变,只需修改这里即可
          destination: test.exchange

接收消息:定义一个 java.util.function.Consumer 即可

@Component
public class ConsumerComponent {
    
    

    @Bean("test")   //注意这里需要对应到 test-out-0 和 test-in-0
    public Consumer<String> consumer(){
    
      // java.util.function.Consumer
        return System.out::println;
    }
}

③接着我们直接启动就可以看到:自动为我们创建了一个新的队列
在这里插入图片描述

我们也可以看到,test.exchange 交换机绑定到了这个队列,路由的 routingKey = # (任意字符串)。
在这里插入图片描述

再次测试
在这里插入图片描述
这样,我们就通过使用 SpringCloud Stream 来屏蔽掉底层 RabbitMQ 来直接进行消息的操作了。

回到目录…

二、SpringCloud Bus

官方文档https://cloud.spring.io/spring-cloud-bus/reference/html/

实际上它就相当于是一个消息总线,可用于向各个服务广播某些状态的更改(比如云端配置更改,可以结合 Config 组件实现动态更新配置,当然我们前面学习的 Nacos 其实已经包含这个功能了)或其他管理指令。

这里我们也是简单使用一下吧,Bus 需要基于一个具体的消息队列实现,比如 RabbitMQ 或是 Kafka,这里我们依然使用 RabbitMQ。

我们将最开始的微服务拆分项目继续使用,比如现在我们希望借阅服务的某个接口调用时,能够给用户服务和图书服务发送一个通知
在这里插入图片描述

1.1 添加依赖

①父工程作 SpringCloud 的版本管理:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2021.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

②在 bookservice、userservice、borrowservice 三个服务中添加 bus-amqp 依赖:

<!-- Bus对很多消息队列都有实现: -amqp、-rocketmq、-kafka -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

③只需要在其中一个服务中添加此依赖即可,这里就选 borrowservice 吧

<!-- 用于消息通知的接口 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

回到目录…

1.2 配置文件

①在三个服务中进行 RabbitMQ 的相关信息配置:

spring:
  rabbitmq:
    addresses: 1.15.76.95
    username: admin
    password: 123456
    virtual-host: /test

②仅在 borrowservice 中配置端口暴露:

management:
  endpoints:
    web:
      exposure:
        include: "*"    #暴露端点,一会儿用于提醒刷新

然后启动我们的三个服务器,可以看到多了一个交换机:
在这里插入图片描述

该交换机绑定了三个服务各自的消息队列,这样就可以监听并接收到消息了:
在这里插入图片描述

现在我们访问一下 borrowservice 的接口:POST http://localhost:8082/actuator/busrefresh
在这里插入图片描述

此接口是用于通知别人进行刷新,可以看到调用之后,消息队列中成功出现了一次消费:
在这里插入图片描述

回到目录…

1.3 实现配置动态更新

现在我们结合之前学习的 SpringCloud之Config配置中心,来看看是不是可以做到通知之后所有的配置动态刷新了。

①创建 config 服务端

a. 创建一个新的项目 config-server,并导入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

b. 写启动类,用 @EnableConfigServer 注解修饰:

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

c. 创建配置文件,并且添加本地仓库的一些信息:

server:
  port: 8700
spring:
  application:
    name: configserver
  cloud:
    config:
      server:
        git:
          # 这里填写的是本地仓库地址,远程仓库直接填写远程仓库地址 http://git...
          uri: file://F:/Git/SpringCloudBus-Config
          # 默认分支设定为你自己本地或是远程分支的名称
          default-label: master

d. 使用 Git 指令创建本地仓库,并将配置文件提交到仓库中:
在这里插入图片描述

# 初始化仓库
git init
# 将配置文件添加标记
git add .
# 将标记的文件提交到本地仓库
git commit -m 'yml'

②客户端的配置

a. 我们的 bookservice 服务需要从服务器读取配置文件,首先需要添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

b. 编写 bootstrap.yml (在 application.yml 加载之前,实现配置文件远程获取)

spring:
  cloud:
    config:
      # 名称,其实就是文件名称
      name: bookservice
      # 配置服务器的地址
      uri: http://localhost:8700
      # 环境
      profile: dev
      # 分支
      label: master

c. 编写一个测试的接口,查看是否能够实时刷新配置

@RefreshScope // 实现动态刷新
@RestController
public class BookController {
    
    

    @Value("${test.value}")
    private String val;

    @GetMapping("/test")
    public void test() {
    
    
        System.out.println("test.value: " + val);
    }
}

③测试

  1. 我们第一次访问接口:http://localhost:8081/test,得到结果 test.value:3
  2. 修改本地仓库的配置文件内容,记得更新后的文件必须提交到本地仓库。
  3. 访问 borrowservice 的接口:/actuator/busrefresh [POST],通知其它服务刷新。
    在这里插入图片描述
  4. 再次访问图书服务的接口:http://localhost:8081/test,得到结果 test.value:4
    在这里插入图片描述
    在这里插入图片描述

回到目录…


总结:
提示:这里对文章进行总结:
本文是对SpringCloud消息组件的学习,第一个组件是 SpringCloud Stream,实现消息队列的相关操作;第二个组件是 SpringCloud Bus,借助消息驱动来实现将消息广播到各个服务中,作为消息总线可实现服务配置动态更新。

猜你喜欢

转载自blog.csdn.net/qq15035899256/article/details/129972696
今日推荐