RefreshScope注解类实例化基本流程
nacos如何通过RefreshScope注解进行属性刷新
RefreshScope
注解原理说了几篇,接着这篇文章的刷新问题。回到NacosContextRefresher
的registerNacosListener
来,在接受到有配置修改的情况下,会进行监听器通知,然后这里面会进行RefreshEvent
事件的通知:
RefreshEventListener的handle
主要是在RefreshEventListener
这个监听器进行环境属性源的刷新,以及scope
被代理对象缓存的释放。具体来看下这么做的。
ContextRefresher的refresh
其实这个里面的scope
是RefreshScope
对象,scope被代理缓存失效就是靠他的,但是前面会先进行环境的刷新,为什么呢,因为需要刷新属性配置源,才可以刷新属性配置对象ConfigurationProperties
属性,才可以在创建被代理对象的时候进行属性注入和配置属性对象的属性绑定。
public synchronized Set<String> refresh() {
Set<String> keys = refreshEnvironment();//刷新环境属性源
this.scope.refreshAll();//刷新的地方
return keys;
}
refreshEnvironment
这里做的就是先获取老的配置属性源,然后刷新配置属性,然后比对新的和老的区别,获取有改变的属性源key
集合返回。
public synchronized Set<String> refreshEnvironment() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());//获取老的配置属性源
addConfigFilesToEnvironment();//刷新配置文件
Set<String> keys = changes(before,//获取修改的属性源key
extract(this.context.getEnvironment().getPropertySources())).keySet();
//通知事件,通知配置属性对象去重新加载属性
this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
return keys;
}
addConfigFilesToEnvironment
这里就开启了一个新的上下文,然后用监听事件去加载新配置,然后替换掉老的。
/* For testing. */ ConfigurableApplicationContext addConfigFilesToEnvironment() {
ConfigurableApplicationContext capture = null;
try {
//创建新的环境去接受新配置
StandardEnvironment environment = copyEnvironment(
this.context.getEnvironment());
//创建新的环境去加载配置
SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class)
.bannerMode(Mode.OFF).web(WebApplicationType.NONE)
.environment(environment);
//添加跟配置文件加载有关的
builder.application()
.setListeners(Arrays.asList(new BootstrapApplicationListener(),
new ConfigFileApplicationListener()));
capture = builder.run();
if (environment.getPropertySources().contains(REFRESH_ARGS_PROPERTY_SOURCE)) {
environment.getPropertySources().remove(REFRESH_ARGS_PROPERTY_SOURCE);
}
MutablePropertySources target = this.context.getEnvironment()
.getPropertySources();
String targetName = null;
for (PropertySource<?> source : environment.getPropertySources()) {
String name = source.getName();
if (target.contains(name)) {
targetName = name;
}
if (!this.standardSources.contains(name)) {
if (target.contains(name)) {
//有同名的就替换老的属性源
target.replace(name, source);
}
else {
if (targetName != null) {
target.addAfter(targetName, source);
}
else {
// targetName was null so we are at the start of the list
target.addFirst(source);
targetName = name;
}
}
}
}
}
finally {
ConfigurableApplicationContext closeable = capture;
...
}
return capture;
}
changes获取新老之间有差异的属性源key集合
进行每个属性源key
的比较,然后取出不同的。
private Map<String, Object> changes(Map<String, Object> before,
Map<String, Object> after) {
Map<String, Object> result = new HashMap<String, Object>();
for (String key : before.keySet()) {
if (!after.containsKey(key)) {
result.put(key, null);
}
else if (!equal(before.get(key), after.get(key))) {
result.put(key, after.get(key));
}
}
for (String key : after.keySet()) {
if (!before.containsKey(key)) {
result.put(key, after.get(key));
}
}
return result;
}
还有通知和scope
刷新没说,后面讲。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵