序言
Spring Cloud Bus将轻量级消息代理程序链接到分布式系统的节点。然后可以将其用于广播状态更改(例如配置更改)或其他管理指令。当前唯一的实现是使用AMQP代理作为传输,但是其他传输的路线图上仍具有相同的基本功能集(还有一些取决于传输)。
此文章仅限入门 SpringCloud版本为 Greenwich
就是说在使用了一些分布式配置中心后(这里以Spring Cloud Config为例),这配置的刷新,一般我们都会重启,但是我们使用了Spring Cloud Bus后啊,就可以做到这些配置的热更新。
窥探
假设我们现在已经有一个项目使用了Spring Cloud Config 并且使用git 作为配置文件的管理处啊。那么我们可以在项目的依赖中加入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
并且这个项目yml加入
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: '*'
这里啊我方便测试 我设置了 include: '*'
按道理可以,只引入-refresh
就行了。
然后这里我们controller 里加入一个注解 @RefreshScope
@RestController
@RefreshScope
public class OrderController {
@Value("${fulinlin.name}")
String fulinlin;
@GetMapping("/getConfig")
public String getConfig() {
return fulinlin;
}
}
然后呢我们在git中 更新这个 fulinlin.name
这个属性后,我们用命令调用一下/actuator/refresh
接口
curl -X POST http://localhost:7001/actuator/refresh
然后呢在控制台中会打印一串日志,这个串日志呢就是,在从配置中心啊重新获取配置。然后我们在访问
http://localhost:7001/getConfig
可以发现这个配置啊已经刷新了。
使用
如果我们这个项目做了个集群,难道我们要一个一个的去调用这个接口,做刷新吗?有没有一种简单的方式呢?对就是bus。大概是这样的,我们引用这个bus啊 结合mq官方有 rabbitmq kafka的实现,
然后每个引用bus的服务 都连接这个mq,启动的时候给mq中创建一个队列,然后这些队列都会有同一个订阅者
然后在我们的服务中专门有一个监听,来监听这个创建队列,然后只要有一个服务提交了刷新请求,这些服务呢都会受到刷新的请求,这样所有服务都刷新了。
在依赖中加入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
这里就使用rabbitmq了 kafka 其实使用起来跟这个没啥区别的。
然后呢controller保持不变
@RestController
@RefreshScope
public class OrderController {
@Value("${fulinlin.name}")
String fulinlin;
@GetMapping("/getConfig")
public String getConfig() {
return fulinlin;
}
}
这里可以使用 -Dserver.port
多起几台服务方便测试。启动后我们在rabbimq的后台查看一下是否有队列进行创建
可以看到有一个springCloudBus
的一个交换器 是一个topic的类型,这里你可以理解为是一个发布订阅模式。
我们在git上事先先修改下 fulinlin.name
这个属性。
然后在命令中发送
curl -X POST http://localhost:7001/actuator/bus-refresh
注意啊这里是 bus-refresh
然后呢你看控制台,打印了一串有关重新拉取的日志。
然后你在刷新下请求看下,是不是这个fulinlin.name
这个属性 已经更新了。
注意
本地配置中心
如果是使用的是本地配置中心。那么你的配置中心需要重启一下,切记啊,因为本地配置中心在启动的时候读取的文件是不会因为修改而重新读取的!!!
刷新范围
我们希望可以刷新微服务中某个具体实例的配置
Spring Cloud Bus对这种场景也有很好的支持:/actuator/bus-refresh
接口还提供了destination
参数,用来定位具体要刷新的应用程序。比如,我们可以请求/actuator/bus-refresh?destination=customers:9000
,此时总线上的各应用实例会根据destination
属性的值来判断是否为自己的实例名,若符合才进行配置刷新,若不符合就忽略该消息。
destination
参数除了可以定位具体的实例之外,还可以用来定位具体的服务。定位服务的原理是通过使用Spring
的PathMatecher
(路径匹配)来实现,比如:/actuator/bus-refresh?destination=customers:**
(以冒号的路径分隔符:)来确定一个实例是否处理该消息,该配置的请求会触发customers
服务的所有实例进行刷新。
优化
这里是使用任意的一个服务端口来刷新配置了,其实你把这个工作交给配置中心也是没问题的。在配置中心中加入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
请求配置中心的 /actuator/bus-refresh
就可以做到配置的刷新了。
这里始终要调取url,我们可以把这一步交个哦webhook
来做啊
但是webhook
不管哪个平台都会带一点参数,所以我们在配置中心自己定义下。
@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
@RestController
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/bus-refresh")
public String busRefresh() {
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("content-type","application/json;charset=UTF-8");
return restTemplate.postForObject("http://localhost:8888/actuator/bus-refresh", httpHeaders, String.class);
}
}
然后在对应代码平台的webhook
中配置一下你自定义的 url ,这样就实现了你提交一次就动态更新啦。
此文章仅限入门,切记啊不会用找不到多去官网看文档!