什么是springcloud-bus
- spring cloud是按照spring的配置对一系列微服务框架的集成,spring cloud bus是其中一个微服务框架,用于实现微服务之间的通信。
- spring cloud bus整合 java的事件处理机制和消息中间件消息的发送和接受,主要由发送端、接收端和事件组成。针对不同的业务需求,可以设置不同的事件,发送端发送事件,接收端接受相应的事件,并进行相应的处理。
- 目前 Spring Cloud Bus 支持两种消息代理:RabbitMQ 和 Kafka
- 需要配合springcloud config使用
原理
- 流程
- 发送端(endpoint)构造事件event,将其publish到context上下文中(spring cloud bus有一个父上下文,bootstrap,
- 然后将事件发送到channel中(json串message)
- 接收端从channel中获取到message,将message转为事件event
- 然后将event事件publish到context上下文中
- 最后接收端(Listener)收到event,调用服务进行处理。
整个流程中,只有发送/接收端从context上下文中取事件和发送事件是需要我们在代码中明确写出来的,其它部分都由框架封装完成。
- Spring Cloud Stream
- Spring Cloud Bus是基于Spring Cloud Stream基础之上而做的封装。Spring Cloud Stream是Spring Cloud家族中一个构建消息驱动微服务的框架。
-
Spring Cloud Stream Application
- Application通过inputs或outputs来与SpringCloud Stream中的 Binder交互,通过配置来binding
- 而Spring Cloud Stream的 Binder负责与中间件交互。
- 所以只需要搞清楚如何与Spring Cloud Stream交互就可以方便使用消息驱动的方式。
-
持久化
- 消息事件的持久化是必不可少的。Spring Cloud Stream可以动态地选择一个消息队列是否需要持久化。
-
Binding
- Binding 是通过配置把应用与Spring Cloud Stream的 Binder绑定在一起的
- 之后只需要修改Binding 的配置来达到动态修改topic、exchange、type等一系列信息,而不需要修改一行代码。
-
Binder
- Binder是Spring Cloud Stream 的一个抽象概念,是应用与消息中间件之间的黏合剂。目前Spring Cloud Stream实现了Kafka和 Rabbit等消息中间件的 Binder。
- 通过Binder,可以很方便地连接消息中间件,可以动态地改变消息的destinations(对应于Kaf-ka 的 topic,Rabbit 的exchanges),这些都可以通过外部配置项做到。通过配置,不需要修改一行代码,就能实现消息中间件的更换。
-
分区支持
- Spring Cloud Stream支持在给定应用程序的多个实例之间对数据进行分区。在分区方案中,物理通信介质(如topic)被视为多个分区。
- Spring Cloud Stream为统一实现分区处理用例提供了一个通用抽象。无论代理本身是自然分区(如Kafka)还是非自然分区(如RabbitMQ),都可以使用分区。
-
订阅/发布
-
消息的发布(Publish)和订阅(Subscribe)是事件驱动的经典模式
- SpringCloud Stream的数据交互也是基于这个思想。生产者把消息通过某个topic广播出去(Spring CloudStream 中的destinations)。
- 其他的微服务通过订阅特定topic来获取广播出来的消息,以触发业务的进行。
- 这种模式极大地降低了生产者与消费者之间的耦合。即使有新的应用引入,也不需要破坏当前系统的整体结构。
-
消费者分组
- Spring Cloud Stream的意思基本与Kafka一致。
- 为了防止同一个事件被重复消费,只要把这些应用放置于同一个“group”中,就能够保证消息只会被其中一个应用消费一次。
- 每个binding 都可以使用以下方式来指定分组名称
-
-
- Spring Cloud Bus是基于Spring Cloud Stream基础之上而做的封装。Spring Cloud Stream是Spring Cloud家族中一个构建消息驱动微服务的框架。
spring.cloud.stream.bindings.<channelName>.group = xxx
下图中Stream 的消费者分组设置,属性值分别设置为
spring.cloud.stream.bind-ings.<channelName>.group=hdfsWrite
spring.cloud.stream.bindings.<channelName>.group=average.
安装rabbitmq
- 安装并启动rabbitmq
Java实现springcloud-bus
动态刷新配置
- 使用 Spring Cloud Bus 动态刷新配置需要配合 Spring Cloud Config 一起使用,我们使用上一章springcloud-config中的config-server、config-client模块来演示下该功能
给config-server添加消息总线支持
- 在pom.xml中添加相关依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 添加配置文件application-amqp.yml,主要是添加了RabbitMQ的配置及暴露了刷新配置的Actuator端点;
server:
port: 8904
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://gitee.com/xxx.git
username: test
password: 123456
clone-on-start: true # 开启启动时直接从git获取配置
rabbitmq: #rabbitmq相关配置
host: localhost
port: 5672
username: guest
password: guest
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: 'bus-refresh'
给config-client添加消息总线支持
- 在pom.xml中添加相关依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
- 添加配置文件bootstrap-amqp1.yml及bootstrap-amqp2.yml用于启动两个不同的config-client,两个配置文件只有端口号不同;
server:
port: 9004
spring:
application:
name: config-client
cloud:
config:
profile: dev #启用环境名称
label: dev #分支名称
name: config #配置文件名称
discovery:
enabled: true
service-id: config-server
rabbitmq: #rabbitmq相关配置
host: localhost
port: 5672
username: guest
password: guest
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/
management:
endpoints:
web:
exposure:
include: 'refresh'
动态刷新配置演示
- 先启动eureka-server,以application-amqp.yml为配置启动config-server,以bootstrap-amqp1.yml为配置启动config-client,以bootstrap-amqp2.yml为配置再启动一个config-client,启动后注册中心显示如下:
- 启动所有服务后,我们登录RabbitMQ的控制台可以发现Spring Cloud Bus 创建了一个叫springCloudBus的交换机及三个以 springCloudBus.anonymous开头的队列:
- 我们先修改Git仓库中dev分支下的config-dev.yml配置文件:
# 修改前信息
config:
info: "config info for dev(dev)"
# 修改后信息
config:
info: "update config info for dev(dev)"
- 调用注册中心的接口刷新所有配置:http://localhost:8904/actuator/bus-refresh
- 刷新后再分别调用http://localhost:9004/configInfo 和http://localhost:9005/configInfo获取配置信息,发现都已经刷新了;
update config info for dev(dev)
- 如果只需要刷新指定实例的配置可以使用以下格式进行刷新:
http://localhost:8904/actuator/bus-refresh/{destination}
- 我们这里以刷新运行在9004端口上的config-client为例http://localhost:8904/actuator/bus-refresh/config-client:9004
配合WebHooks使用
- WebHooks相当于是一个钩子函数,我们可以配置当向Git仓库push代码时触发这个钩子函数
- 这里以Gitee为例来介绍下其使用方式,这里当我们向配置仓库push代码时就会自动刷新服务配置了。