背景
当我们更新了ConfigServer中的相关配置(本文讲的是基于MySQL的配置存储),想要在不关闭重启服务的情况下,对配置进行更新,这时就需要用到Spring提供的配置刷新功能。
配置刷新的原理都是通过调用各个服务的 /actuator/refresh 接口,从而触发重新拉取ConfigServer配置。
配置更新的各种姿势
1. 手动调用各个服务的 /actuator/refresh 接口
首先需要确保该端点处理开启状态
management:
endpoints:
web:
exposure:
include: health,info,refresh # 加入refresh开启端口
在需要刷新的配置上,加上@RefreshScope注解,如下是一个token过期时间的配置:
@Component
@Data
@RefreshScope
public class TokenProperties {
@Value("${token.expire-time}")
private Integer tokenExpireTime;
}
手动调用 localhost:8080/actuator/refresh
缺点,SpringCloud会有很多服务,而且一个服务会有多个节点,需要手动执行多次。
2. 使用Spring Cloud Bus消息总线触发配置刷新
Spring Cloud Bus会向外提供一个http接口,即图中的/bus/refresh。我们将这个接口配置到远程的git的webhook上,当git上的文件内容发生变动时,就会自动调用/bus-refresh接口。Bus就会通知config-server,config-server会发布更新消息到消息总线的消息队列中,其他服务订阅到该消息就会信息刷新,从而实现整个微服务进行自动刷新。

了解下其刷新原理,本文不做展开,具体细节可参考文章(上面的图也是来自这位博主) https://www.cnblogs.com/babycomeon/p/11141160.html
优点,配置刷新变可触发重新拉取配置,无需手动调用
3. 自定义刷新接口(集成actuator/refresh)
为什么不使用SpringCloudBus?
答:当我们一次性修改某个服务的多项配置,或者你并不想这个配置马上去刷新,而是等待某个时间点你在去一次性刷新该服务配置,这时候自定义刷新配置更符合你的需求。
其实原理就是将第一种方式(actuator/refresh调用)进行封装,通过服务发现获取到该服务的多个实例,依次去调用各个实例的 actuator/refresh接口。
对外提供一个接口刷新配置,关键代码如下:
@RestController
@Slf4j
public class ConfigRefreshController {
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/api/config/refresh")
public String refresh (@Valid @NotEmpty String serviceName, ServerHttpResponse serverHttpResponse) {
// 获取改服务的实例列表
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
List<ConfigRefreshResult> resultList = new ArrayList<>(serviceInstances.size());
// 依次调用实例的刷新方法
serviceInstances.forEach(serviceInstance -> {
ConfigRefreshResult configRefreshResult = new ConfigRefreshResult();
configRefreshResult.setServiceName(serviceName);
configRefreshResult.setUrl(serviceInstance.getUri().toString());
try {
String result = HttpUtil.httpPost(serviceInstance.getUri() + "/actuator/refresh", null);
configRefreshResult.setResult(result);
} catch (Exception e) {
log.error(JSON.toJSONString(serviceInstance));
e.printStackTrace();
configRefreshResult.setResult(e.getMessage());
}
resultList.add(configRefreshResult);
});
serverHttpResponse.setStatusCode(HttpStatus.OK);
serverHttpResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
return JSON.toJSONString(resultList);
}
}
网友评论