一灰灰blog 一灰灰blog
首页
  • InfluxDB
  • MongoDB
  • MySql
  • 基础系列
  • DB系列
  • 搜索系列
  • MQ系列
  • WEB系列
  • 中间件
  • 运维
  • SpringSecurity
  • SpringCloud
  • QuickAlarm
  • QuickCrawer
  • QuickFix
  • QuickMedia
  • QuickSpi
  • QuickTask
  • 高可用
  • 分类
  • 标签
  • 归档
  • 收藏
  • 关于
GitHub (opens new window)

一灰灰blog

资深搬运工
首页
  • InfluxDB
  • MongoDB
  • MySql
  • 基础系列
  • DB系列
  • 搜索系列
  • MQ系列
  • WEB系列
  • 中间件
  • 运维
  • SpringSecurity
  • SpringCloud
  • QuickAlarm
  • QuickCrawer
  • QuickFix
  • QuickMedia
  • QuickSpi
  • QuickTask
  • 高可用
  • 分类
  • 标签
  • 归档
  • 收藏
  • 关于
GitHub (opens new window)
  • 基础系列

    • 配置

      • 【基础系列】SpringBoot基础篇配置信息之如何读取配置信息
      • 【基础系列】SpringBoot基础篇配置信息之多环境配置信息
      • 【基础系列】SpringBoot基础篇配置信息之自定义配置指定与配置内引用
      • 【基础系列】SpringBoot配置信息之配置刷新
        • I. 配置动态刷新
          • 1. ContextReferer
          • 2. 代码演示
          • 3. 实例演示
        • II. 配置变更监听
          • 1. 配置变更监听
          • 2. 实测
        • III. 其他
          • 0. 项目
          • 1. 一灰灰Blog
          • 2. 声明
          • 3. 扫描关注
      • 【基础系列】SpringBoot配置信息之默认配置
      • 【基础系列】实现一个自定义配置加载器(应用篇)
      • 【基础系列】SpringBoot配置篇之PropertySource加载Yaml配置文件实例演示
      • 【基础系列】ConfigurationProperties配置绑定中那些你不知道的事情
      • 【基础系列】SpringBoot基础篇@Value中哪些你不知道的知识点
      • 【基础系列】SpringBoot之自定义配置源的使用姿势
      • 【基础系列】SpringBoot @Value之字面量及SpEL知识点介绍篇
      • 【基础系列】SpringBoot应用篇@Value注解支持配置自动刷新能力扩展
      • 【基础系列】基于maven多环境配置
    • AOP

    • Bean

    • SpEL

    • 事件

    • 国际化

    • 定时器

    • 日志

  • DB系列

  • 搜索系列

  • MQ系列

  • WEB系列

  • 中间件

  • 运维

  • SpringSecurity

  • SpringCloud

  • Spring系列
  • 基础系列
  • 配置
一灰灰
2018-09-22

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

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

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

# I. 配置动态刷新

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

# 1. ContextReferer

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

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

<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

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

# 2. 代码演示

配置文件: application.yml

biz:
  refresh: ${random.long}
  key: refresh-test

rest:
  uuid: ${random.uuid}

server:
  port: 8081
1
2
3
4
5
6
7
8
9

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

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

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

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

测试Controller如下

@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();
    }
}
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

# 3. 实例演示

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

实例演示

说明

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

# II. 配置变更监听

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

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

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
2
3
4
5
6
7
8
9
10
11

# 1. 配置变更监听

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

@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);
    }
}
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

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

# 2. 实测

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

配置刷新事件监听

# III. 其他

# 0. 项目

  • 工程:spring-boot-demo (opens new window)
  • modal: spring-boot-demo#002-properties (opens new window)

# 1. 一灰灰Blog

  • 一灰灰Blog个人博客 https://blog.hhui.top (opens new window)
  • 一灰灰Blog-Spring专题博客 http://spring.hhui.top (opens new window)

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

# 2. 声明

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

  • 微博地址: 小灰灰Blog (opens new window)
  • QQ: 一灰灰/3302797840

# 3. 扫描关注

一灰灰blog

QrCode

知识星球

goals

编辑 (opens new window)
#Config
上次更新: 2021/10/15, 19:56:22
【基础系列】SpringBoot基础篇配置信息之自定义配置指定与配置内引用
【基础系列】SpringBoot配置信息之默认配置

← 【基础系列】SpringBoot基础篇配置信息之自定义配置指定与配置内引用 【基础系列】SpringBoot配置信息之默认配置→

最近更新
01
【基础系列】基于maven多环境配置
04-25
02
【WEB系列】内嵌Tomcat配置Accesslog日志文件生成位置源码探索
04-24
03
【搜索系列】ES查询常用实例演示
04-18
更多文章>
Theme by Vdoing | Copyright © 2017-2022 一灰灰Blog
MIT License | 鄂ICP备18017282号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×