Spring Cloud @RefreshScope和@EventListener实现Nacos配置更新监听

问题描述

使用@RefreshScope会刷新在Sprign IOC中所有Bean中使用@Value的值,但是在配置类中使用方法去配置的其他类参数并不会改变,例如

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
@Slf4j
@Configuration
@RefreshScope
public class SentinelConfig {
@Bean
public ZuulFilter sentinelZuulPreFilter() {
return new SentinelZuulPreFilter();
}

@Bean
public ZuulFilter sentinelZuulPostFilter() {
return new SentinelZuulPostFilter();
}

@Bean
public ZuulFilter sentinelZuulErrorFilter() {
return new SentinelZuulErrorFilter();
}

@PostConstruct
public void init() {
ZuulBlockFallbackManager.registerProvider(new MyBlockFallbackProvider());
Config config = ConfigService.getAppConfig();
//Nacos后台配置更新,flowRules并不会改变,需要手动loadRules
String flowRulesJson = config.getProperty("sentinel.flowRules",
"[{\"burst\":0,\"controlBehavior\":0,\"count\":3.0,\"grade\":1,\"intervalSec\":1,\"maxQueueingTimeoutMs\":500,\"resource\":\"appblog-service\",\"resourceMode\":1}]");
Set<GatewayFlowRule> flowRules = JSON.parseObject(flowRulesJson, new TypeReference<Set<GatewayFlowRule>>(){});
GatewayRuleManager.loadRules(flowRules);
}
}

解决方案

1
2
3
4
5
//使用此方法监听事件
@EventListener
public void envListener(EnvironmentChangeEvent 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
36
37
38
39
40
@Slf4j
@Configuration
@RefreshScope
public class SentinelConfig {
@Value("${sentinel.flowRules:[{\"burst\":0,\"controlBehavior\":0,\"count\":3.0,\"grade\":1,\"intervalSec\":1,\"maxQueueingTimeoutMs\":500,\"resource\":\"appblog-service\",\"resourceMode\":1}]}")
private String flowRulesJson;

@Bean
public ZuulFilter sentinelZuulPreFilter() {
return new SentinelZuulPreFilter();
}

@Bean
public ZuulFilter sentinelZuulPostFilter() {
return new SentinelZuulPostFilter();
}

@Bean
public ZuulFilter sentinelZuulErrorFilter() {
return new SentinelZuulErrorFilter();
}

@PostConstruct
public void init() {
ZuulBlockFallbackManager.registerProvider(new MyBlockFallbackProvider());
Config config = ConfigService.getAppConfig();
String flowRulesJson = config.getProperty("sentinel.flowRules",
"[{\"burst\":0,\"controlBehavior\":0,\"count\":3.0,\"grade\":1,\"intervalSec\":1,\"maxQueueingTimeoutMs\":500,\"resource\":\"appblog-service\",\"resourceMode\":1}]");
Set<GatewayFlowRule> flowRules = JSON.parseObject(flowRulesJson, new TypeReference<Set<GatewayFlowRule>>(){});
GatewayRuleManager.loadRules(flowRules);
}

@EventListener
public void envChangeListener(EnvironmentChangeEvent event) {
log.info("Sentinel配置刷新");
log.info(flowRulesJson);
Set<GatewayFlowRule> flowRules = JSON.parseObject(flowRulesJson, new TypeReference<Set<GatewayFlowRule>>(){});
GatewayRuleManager.loadRules(flowRules);
}
}

原因分析

在调用刷新方法是会产生一个EnvironmentChangeEvent事件。进入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;
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :