spring cloud的RefreshScope注解进行热部署
需要热加载的bean需要加上@RefreshScope注解,当配置发生变更的时候可以在不重启应用的前提下完成bean中相关属性的刷新。
【spring cloud的RefreshScope注解进行热部署】
经由@RefreshScope修饰的bean将会被RefreshScope代理,其关于bean生命周期的相关方法也在此定义。
@ManagedOperation(description = "Dispose of the current instance of all beans in this scope and force a refresh on next method execution.")
public void refreshAll() {
super.destroy();
this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
RefreshScope代理的bean强制为懒加载,只有在第一次使用的时候才会生成实例,当其需要刷新配置的时候直接调用destory()方法销毁当前bean,这样在刷新配置后在需要生成的bean已经是根据新的配置信息生成,完成bean的热加载。
在spring cloud中,当配置发生变更,将会通过soring cloud bus发送RefreshRemoteApplicationEvent事件给相关应用,在RefreshListener中,开始对于配置的刷新。
public void onApplicationEvent(RefreshRemoteApplicationEvent event) {
Set keys = this.contextRefresher.refresh();
log.info("Received remote refresh request. Keys refreshed " + keys);
}
最终刷新将在refreshContext的refresh()方法中进行。
public synchronized Set refresh() {
Set keys = refreshEnvironment();
this.scope.refreshAll();
return keys;
}public synchronized Set refreshEnvironment() {
Map before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
return keys;
}
在这里的刷新一共被分为两个步骤,首先获取新的配置值与老的配置值进行比对并更新,之后再销毁所有被RefreshScope代理的bean。
在第一步,重点在于获取新的配置值,具体实现在addConfigFilesToEnvironment()方法中。
StandardEnvironment environment = copyEnvironment(
this.context.getEnvironment());
SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class)
.bannerMode(Mode.OFF).web(WebApplicationType.NONE)
.environment(environment);
// Just the listeners that affect the environment (e.g. excluding logging
// listener because it has side effects)
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;
}
}
}
}
此处将会以当前的应用的envionment深克隆一份,并根据复制出来的为依据重新建立一个spring boot application,在新的应用建立过程中,将会重新获取配置值,此处也将获取新的配置值,在新的副本应用建立完毕之后,将会返回其配置值准备与旧的配置值进行比对并更新。
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量