- nacos版本:2.2.0
- springcloud-alibaba版本:2021.0.6.0
- springcloud-commons版本:3.1.8
简单类型配置
@Data
public class LogProperties {
private String testProperty;
}
如果删除testProperty
配置,内存中还有旧的数据。
列表类型配置
@Data
public class LogProperties {
private Set<String> testSet;
}
- 删除set中某个元素,生效
- 删除整个配置项,不生效
Map类型配置
@Data
public class LogProperties {
private boolean enabled = true;
/**
* 不打印日志的参数
*/
private Map<String, Set<String>> excludeRequestParams;
}
- 删除
Set<String>
中的某项配置,生效 - 删除map中某项key,不生效
- 清空整个配置项(删除整个
excludeRequestParams
参数),不生效
配置项删除不生效,但是删除某个元素生效。
对于Map类型,key也算配置项级别,因此删除key不生效
原因分析
首先需要了解Nacos动态刷新原理。
nacos在配置变更后,会重新获取所有远程的配置项,然后利用ConfigDataLoader机制,重新覆盖spring内的配置项。因此,对于已经在远程删除的配置项,nacos无法做到删除spring配置项。
其实很好理解。假如配置类中有一个默认的属性
enabled = true
,总不能因为配置文件中没有这个配置项,就把该配置删除(置为null)吧!
根本原因是spring自身在rebind bean的时候,只是调用了bean的destroy方法和初始化方法。而不是重新创建一个bean,因此对于bean的配置属性,如果环境中没有,是无法修改的。
private boolean rebind(String name, ApplicationContext appContext) {
try {
Object bean = appContext.getBean(name);
if (AopUtils.isAopProxy(bean)) {
bean = ProxyUtils.getTargetObject(bean);
}
if (bean != null) {
if (getNeverRefreshable().contains(bean.getClass().getName())) {
return false;
}
appContext.getAutowireCapableBeanFactory().destroyBean(bean);
appContext.getAutowireCapableBeanFactory().initializeBean(bean, name);
return true;
}
}
catch (RuntimeException e) {
this.errors.put(name, e);
throw e;
}
catch (Exception e) {
this.errors.put(name, e);
throw new IllegalStateException("Cannot rebind to " + name, e);
}
return false;
}
解决方案一
利用spring刷新配置的原理,在destroy和init方法上进行处理
在配置类中添加destroy方法
@PreDestroy
public void destroy() {
//解决nacos无法删除配置问题
log = new LogProperties();
}
LogProperties是一个
@NestedConfigurationProperty
这样,spring在刷新配置时,就会调用到该销毁方法,将属性先销毁。
然后,在init中会自动从环境中获取配置,给该属性赋值。
如果LogProperties是采用@PostConstruct使用的,还需要在使用该配置的bean上加注解
@RefreshScope
@PostConstruct public void init() { logProperties = SpringUtil.getBean(GennHubGatewayProperties.class).getLog();
因为只有加了
@RefreshScope
的bean,才会触发spring的刷新。
如果是直接用外层配置类拿的属性,是不需要这样的。
因此,对于@NestedConfigurationProperty
,在引用这些配置时,建议使用注入的原始配置类。