【基础系列】SpringBoot配置信息之配置刷新

文章目录
  1. I. 配置动态刷新
    1. 1. ContextReferer
    2. 2. 代码演示
    3. 3. 实例演示
  2. II. 配置变更监听
    1. 1. 配置变更监听
    2. 2. 实测
  3. III. 其他
    1. 0. 项目
    2. 1. 一灰灰Blog
    3. 2. 声明
    4. 3. 扫描关注

配置的刷新,从第一篇就提出了这个问题,但是一直都没有说到,那么配置加载完毕之后能否在主动刷新呢?

如果对SpringCloud有了解的话,会直到有个配置中心的微服务,专门就是来做配置远程拉取,当然也支持刷新了,这是否意味着可以支持刷新呢,如果支持该怎么做?

I. 配置动态刷新

本篇将介绍并演示如何实现配置信息的刷新,但不会涉及到底层的实现原理,想要探究里面的神奇,可以网上google一下,或者期待后续的源码分析篇

1. ContextReferer

我们这里主要借助这个类来实现配置刷新,至于从哪里捞出来的这个东西,从Spring-Cloud-Config出发,看了下它怎么玩的,然后依葫芦画瓢

这个类全路径为 org.springframework.cloud.context.refresh.ContextRefresher,因此你的SpringBoot项目需要做一点修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

接下来就简单了,直接调用这个类的refresh()方法就可以了,just so easy~

2. 代码演示

配置文件: application.yml

1
2
3
4
5
6
7
8
9
biz:
refresh: ${random.long}
key: refresh-test

rest:
uuid: ${random.uuid}

server:
port: 8081

读取配置的bean,演示了两种获取方式,分别如下

1
2
3
4
5
6
7
@Data
@Component
@ConfigurationProperties(prefix = "biz")
public class BizConfig {
private String key;
private Long refresh;
}

开启刷新的@Value注解方式,注意下面的@RefreshScoe注解,这个必须有,负责更新后的配置不会同步

1
2
3
4
5
6
7
@Data
@RefreshScope
@Component
public class ValueConfig {
@Value("${rest.uuid}")
private String uuid;
}

测试Controller如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@RestController
public class DemoController {
@Autowired
private ContextRefresher contextRefresher;

@Autowired
private BizConfig bizConfig;

@Autowired
private ValueConfig valueConfig;

@GetMapping(path = "/show")
public String show() {
JSONObject res = new JSONObject();
res.put("biz", JSONObject.toJSONString(bizConfig));
res.put("uuid", valueConfig.getUuid());
return res.toJSONString();
}

@GetMapping(path = "/refresh")
public String refresh() {
new Thread(() -> contextRefresher.refresh()).start();
return show();
}
}

3. 实例演示

启动上面的应用,然后开启愉快的测试,调用refresh接口,发现每次的返回都不一样(因为配置文件使用了random随机生成),但是访问show接口时,每次返回的都是一样的,也就是说refresh接口中确实实现了配置的刷新

实例演示

说明

  • 使用ConfigurationProperties方式获取注解时,自动支持刷新配置
  • 使用@Value注解的方式,需要开启@RefreshScope注解(上面没有演示不开启这个注解的情况, 建议有兴趣的可以自己尝试一下)

II. 配置变更监听

既然配置能刷新,那么如果我希望获取配置变更的事件,然后做一些其他的事情,是否ok呢?

其实进入 ContextRefresher 的源码,看下refresh接口,就很明确了

1
2
3
4
5
6
7
8
9
10
11
public synchronized Set<String> refresh() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
// 注意这一行,抛出了一个变更事件
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
this.scope.refreshAll();
return keys;
}

1. 配置变更监听

从上面的源码中,借助spring的事件通知机制,很简单就可以知道该怎么做了,来一个简单的demo,这里顺带测试下上面漏掉的不刷新的场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@RestController
public class DemoController {

@Autowired
private ContextRefresher contextRefresher;

@Autowired
private BizConfig bizConfig;

@Autowired
private ValueConfig valueConfig;

@Value("${rest.uuid}")
private String uuid;

@GetMapping(path = "/show")
public String show() {
JSONObject res = new JSONObject();
res.put("biz", JSONObject.toJSONString(bizConfig));
res.put("uuid", valueConfig.getUuid());
res.put("no-refresh", uuid);
return res.toJSONString();
}

@GetMapping(path = "/refresh")
public String refresh() {
new Thread(() -> contextRefresher.refresh()).start();
return show();
}

@EventListener
public void envListener(EnvironmentChangeEvent event) {
System.out.println("conf change: " + event);
}
}

直接将Listener写在Controller类内部… 原则上不推荐上面的写法

2. 实测

依然来个实测,主要注意下控制台的输出即可

配置刷新事件监听

III. 其他

0. 项目

1. 一灰灰Blog

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

3. 扫描关注

一灰灰blog

QrCode

知识星球

goals


打赏 如果觉得我的文章对您有帮助,请随意打赏。
分享到