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
刷新没说,后面讲。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。