1.问题背景
前一篇使用Spring Cloud Config 模拟配置中心, 有时候需要修改配置中心的配置信息, 我们希望实现胚子修改后实时更新,实现的方法也很简单,只需要 config-client的pom.xm中增加actuator监控依赖,因为actuator监控中包含了./refresh端点实现,断点将用于客户端配置信息重新获取和刷新
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
当配置发生变化后, 访问配置信息你回发现还是旧信息, 当通过post请求发送到/refresh端点后配置被更新,例如使用 Postman模拟
验证 http://127.0.0.1:8007/fromByConf 时from表单的信息已经变成最新的,当看到这里的时候问题来了, 再集群环境下,一个配置信息可能应用在好几个应用服务中, 那么每次修改都需要一个服务一个服务维护,那么维护成本很高, 操作很复杂,很容易出错。 我们就会想有没有比较简单省力的处理方法。 比如发送一个配置变更的消息主题,然后让系统中所有相关的微服务实例都知道这条配置变更的消息并更新
2.Spring Cloud Bus简介
Spring Cloud Bus将分布式系统的节点与轻量级消息代理链接。这可以用于广播状态更改(例如配置更改)或其他管理指令。Bus就像一个扩展的Spring Boot应用程序的分布式执行器,也可以用作应用程序之间的通信渠道,当前Spring Cloud Bus支持RabbitMQ和Kafka ,只要Spring Cloud Bus AMQP和RabbitMQ在类路径上,任何Spring Boot应用程序都会尝试联系上一个RabbitMQserver其spring.rabbitmq.addresses的默认值为localhost:5672
Spring Cloud Bus在类路径上检测到自己,它会通过添加Spring Boot自动配置来工作。要启用总线需要添加Spring-cloud-starter-bus-smqp或者 spring-cloud-starter-bus-kafka,依赖到依赖管理器, 其次
确保代理(RabbitMQ或Kafka)配置真确并已经在主机上运行,其他事情Spring都会帮助完成,
Spring Cloud Bus消息总线支持向监听特定服务的所有节点发送消息,/bus/*
执行器命名空间有一些HTTPendpoints,当前有两个端点, 一个是 /bus/env 实现向每个节点的Spring环境发送键/值对 ,另一个是/bus/refresh 实现重新加载每个应用程序的配置,每一个应用程序都有一个服务标识,这个值一般是用冒号分割,这个值将会设置到spring.cloud.bus.id 上默认值是spring.application.name : server.port, HTTP端点接受“目的地”路径参数,例如/busrefresh/customers:9000, 如果设置了目的地,那么之后该服务会执行消息其他服务实例会忽略
3.Spring Cloud Bus+ RabitMQ快速入门
参考代码: GitHub - PNZBEIJINGL/spring-cloud-lab
服务 | IP | 端口 | |
eureka-peer | 127.0.0.1 | 1000 | Eureka服务注册中心 |
config-server | 127.0.0.1 | 8007 | 配置中心服务(使用的GitHub上的仓库) |
config-client | 127.0.0.1 | 8006 | 模拟客户端服务 |
ms-customer | 127.0.0.1 | 8001 | 模拟客户服务 |
1. 扩展config-client 修改pox.xml 增加依赖,Spring Cloud Bus通过添加Spring Boot自动配置依赖spring-boot-starter-actuator和spring-cloud-starter-bus-amqp,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 引入bus-amqp -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2. application.xml 文件中增加RabbitMq配置
server.port=8007
management.security.enabled=false
############ Eureka ################
#服务注册中心IP
eureka.instance.hostname=127.0.0.1
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:1000/eureka/
############ Eureka ################
############ RabbitMQ Config ################
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=test
spring.rabbitmq.password=test
############ RabbitMQ Config END #############
RabbitMQ 信息可以参考 链接:RabbitMQ Server简介和安装教程
可以通过guest/guest登录创建用户,如下图, 新创建的用户can access virtual hosts 设置为不允许接入,点击创建的用户,通过Permisions设置接入许可为 "/"
3. config-client服务使用前一篇文章的测试代码
@RefreshScope
@RestController
public class ConfigController {
//绑定配置
@Value("${from}")
private String from;
@Autowired
private Environment env;
@RequestMapping("/fromByConf")
public String from(){
return this.from;
}
@RequestMapping("/fromByEnv")
public String getFromByEnv(){
return this.env.getProperty("from","undefined");
}
}
4. 将config-client 服务配置复制一份到 ms-customer 服务
5. 启动eureka-peer,config-server ,config-clinet,ms-customer服务,
查看config-clinet,ms-custome服务的启动日志,其中日志里有两部分,一部分是增加了bus/refresh 刷新断点,一部分为使用RabbitMQ的配置信息链接RabbitMQ
o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/bus/refresh],methods=[POST]}" onto public void org.springframework.cloud.bus.endpoint.RefreshBusEndpoint.refresh(java.lang.String)
......
o.s.a.r.c.CachingConnectionFactory : Created new connection: SimpleConnection@4c91f5bf [delegate=amqp://test@192.168.20.134:5672/, localPort= 52148]
2021-12-27 11:09:39.858 INFO 18400 --- [ main] o.s.integration.channel.DirectChannel : Channel 'paramspace:8007.springCloudBusOutput' has 1 subscriber(s).
访问,config-clinet服务 http://127.0.0.1:8007/fromByConf 获取配置服务中的配置 git-dev-1.0
访问,ms-customer 服务 http://127.0.0.1:8001/fromByConf 获取配置服务中的配置 git-dev-1.0
然后在git上修改配置文件中git修改git-dev-1.0 为git-dev-5.0 并使用postman向 http://127.0.0.1:8007/bus/refresh 发送POST请求,请求刷新配置
最后访问 http://127.0.0.1:8007/fromByConf 和 http://127.0.0.1:8001/fromByConf 会返现2个服务获取的配置都已经同时刷新成最新的配置
4.文章总结
如上图Spring Cloud Bus 刷新配置步骤如下
- 提交代码触发post给Server端发送bus/refresh
- Server端接收到请求并发送给Spring Cloud Bus
- Spring Cloud bus接到消息并通知给其它客户端
- 其它客户端接收到通知,请求Server端获取最新配置
- 全部客户端均获取到最新的配置