博主在调研 Spring Cloud Config 跟 Apollo 配置中心的时候,对其中的热更新机制比较有兴趣,并阅读了相关的源码,在这里进行记录,方便以后查看。
调研时使用的 Spring Boot 跟 Spring Cloud 的版本:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.21.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
知识背景
Spring Cloud Config 提供了一套配置中心,结合 Spring Cloud Bus 可实现一套配置的自动热更新。其实通过阅读源码,无论是 Spring Cloud Config 的手动刷新,还是通过 Spring Cloud Bus 通知进行自动刷新配置,最终底层都是使用了Spring Cloud 提供的热更新机制
,换句话说,其实无需使用配置中心,通过手动修改配置文件,触发refresh 端点
也可以触发热更新。
Spring Cloud 热更新机制,支持热更新的配置有三类,分别是:@ConfigurationProperties 注入的配置类
,日志相关
,@RefreshScope 注解的类
。而对于这三类配置,Spring Cloud 提供了两种更新策略,对于前两类,采用类的重新绑定策略
进行更新,而最后的 @RefreshScope,采用了延迟加载跟缓存刷新的策略
。下面将讲解具体的实现方式。
源码阅读
热更新机制的入口为调用ContextRefresher
类的refresh
方法,代码如下:
public synchronized Set<String> refresh() {
// 1. 获取当前配置源信息
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
// 2. 加载配置
addConfigFilesToEnvironment();
// 3. 获取修改了配置值的kd
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
// 4. 发布变更事件
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
// 5. 刷新@refreshScope类
this.scope.refreshAll();
return keys;
}
下面对上面的代码进行解读:
1. 获取当前属性源信息
这里获取环境的所有属性源的信息,但从中去除标准属性源:
private Map<String, Object> extract(MutablePropertySources propertySources) {
Map<String, Object> result = new HashMap<String, Object>();
List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>