SpringBoot动态加载配置⽂件及刷新Bean
需求
系统遇到这样⼀个需求,线上环境在配置⽂件发⽣变动时,可以不⽤经过重启,通过刷新接⼝的⽅式得到配置⽂件的加载,主要⽬的是为了迅速部署,避免因⼿动重启,出现数据或任务丢失的问题
问题
1.程序中如何获取修改后的配置
2.某些配置值是应⽤在bean⾥⾯的,在程序初始化的时候已经注⼊,如何修改这⼀部分。
解决
第⼀步,添加适合⾃⼰springboot版本的Springcloud context依赖,若Springboot版本低,maven可能会引不上⾼版本的context
<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>
我们这⾥参考 Spring-Cloud-Config 主要借助 org.t.refresh.ContextRefresher 这个类来实现配置刷新,因此需要对 SpringBoot 项⽬做⼀点修改。
代码演⽰
配置⽂件: l
server:
refresh: ${random.long}
key: refresh-test
config:
uuid: ${random.uuid}
读取配置的Bean,两种获取⽅式分别如下
@Component
@ConfigurationProperties(prefix = "server")
public class ServerConfig {
private String key;
private Long refresh;
}
开启刷新@Value的注解⽅式,注意下⾯的@RefreshScoe注解,这个必须有,否则更新后的配置不会同步
@RefreshScope
@Component
public class ValueConfig {
@Value("${config.uuid}")
private String uuid;
springcloud和springboot}
测试Controller 如下
@RestController
public class DemoController {
@Autowired
private ContextRefresher contextRefresher;
@Autowired
private ServerConfig serverConfig;
@Autowired
private ValueConfig valueConfig;
@GetMapping(path = "/show")
public String show() {
JSONObject res = new JSONObject();
res.put("biz", JSONString(serverConfig));
res.put("uuid", Uuid());
JSONString();
}
@GetMapping(path = "/refresh")
public String refresh() {
new Thread(() -> fresh()).start();
return show();
}
}
3. 实例演⽰
启动上⾯的应⽤,然后开启愉快的测试,调⽤refresh接⼝,发现每次的返回都不⼀样(因为配置⽂件使
⽤了random随机⽣成),但是访问show接⼝时,每次返回的都是⼀样的,也就是说refresh接⼝中确实实现了配置的刷新。
说明
使⽤ConfigurationProperties⽅式获取注解时,⾃动⽀持刷新配置
使⽤@Value注解的⽅式,需要开启@RefreshScope注解(上⾯没有演⽰不开启这个注解的情况, 建议有兴趣的可以⾃⼰尝试⼀下)II. 配置变更监听
既然配置能刷新,那么如果我希望获取配置变更的事件,然后做⼀些其他的事情,是否ok呢?
其实进⼊ContextRefresher的源码,看下refresh接⼝,就很明确了
public synchronized Set<String> refresh() {
Map<String, Object> before = extract(
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
t.getEnvironment().getPropertySources())).keySet();
// 注意这⼀⾏,抛出了⼀个变更事件
freshAll();
return keys;
}
1. 配置变更监听
从上⾯的源码中,借助spring的事件通知机制,很简单就可以知道该怎么做了
import org.t.environment.EnvironmentChangeEvent;
import t.annotation.Configuration;
import t.event.EventListener;
@Configuration
public class EnvConfiguration{
@EventListener
public void envListener(EnvironmentChangeEvent event) {
System.out.println("conf change: " + event);
}
}
注意下控制台的输出即可