默认情况下 apollo无法刷新 ConfigurationProperties标注的属性实时更新
我查看官方文档他推荐了两种实现思路
@RefrashScope
和通过EnvironmentChangeEvent
这两个都是在spring-cloud-context中提供的
我简单举个例子
/**
* @Description
* @Author changyandong
* @Emoji (゜ - ゜)つ干杯
* @Created Date: 2019/11/20 9:01
* @ClassName MsGatewayProperties
* @Version: 1.0
*/
@Component
@ConfigurationProperties("ms.gateway")
public class MsGatewayProperties {
private MsGatewayUrlProperties url = new MsGatewayUrlProperties();
public MsGatewayUrlProperties getUrl() {
return url;
}
public void setUrl(MsGatewayUrlProperties url) {
this.url = url;
}
}
/**
* @Description
* @Author changyandong
* @Emoji (゜ - ゜)つ干杯
* @Created Date: 2019/11/20 9:02
* @ClassName MsGatewayUrlProperties
* @Version: 1.0
*/
public class MsGatewayUrlProperties {
private String sss;
private String xxx;
public String getSss() {
return sss;
}
public void setSss(String sss) {
this.sss = sss;
}
public String getXxx() {
return xxx;
}
public void setXxx(String xxx) {
this.xxx = xxx;
}
}
然后我创建一个apollo监听类 这里的ConfigChangeService是我们框架封装的 如果自己写的话一个普通的@ApolloConfigChangeListener类即可
/**
* @Description
* @Author changyandong
* @Emoji (゜ - ゜)つ干杯
* @Created Date: 2019/11/20 9:00
* @ClassName MsGatewayAppolloChangeSerivce
* @Version: 1.0
*/
@Component
public class MsGatewayApolloChangeService implements ConfigChangeService, ApplicationContextAware {
private Logger logger = LoggerFactory.getLogger(MsGatewayApolloChangeService.class);
private ApplicationContext applicationContext;
@Override
public void detectConfigChanges(ConfigChangeEvent changeEvent) {
boolean gatewayPropertiesChanged = false;
for (String changedKey : changeEvent.changedKeys()) {
//前缀为spring.cloud.gateway的key发生了改变(gateway的配置发生了改变)
if (changedKey.startsWith("ms.gateway")) {
gatewayPropertiesChanged = true;
break;
}
}
//更新gateway配置
if (gatewayPropertiesChanged) {
refreshGatewayProperties(changeEvent);
}
}
/**
* 更新SpringApplicationContext对象,并更新路由
*
* @param changeEvent
*/
private void refreshGatewayProperties(ConfigChangeEvent changeEvent) {
//更新配置
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
}
@Override
public int getOrder() {
return 1;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
这时他给spring推了一个事件 EnvironmentChangeEvent
这时会触发ConfigurationPropertiesRebinder的onApplicationEvent方法进而触发rebind方法
@Component
@ManagedResource
public class ConfigurationPropertiesRebinder
implements ApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {
private ConfigurationPropertiesBeans beans;
private ApplicationContext applicationContext;
private Map<String, Exception> errors = new ConcurrentHashMap<>();
public ConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {
this.beans = beans;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
/**
* A map of bean name to errors when instantiating the bean.
* @return The errors accumulated since the latest destroy.
*/
public Map<String, Exception> getErrors() {
return this.errors;
}
@ManagedOperation
public void rebind() {
this.errors.clear();
// 这里会把标注了ConfigurationProperties的所有类都扫一遍
for (String name : this.beans.getBeanNames()) {
rebind(name);
}
}
@ManagedOperation
public boolean rebind(String name) {
if (!this.beans.getBeanNames().contains(name)) {
return false;
}
// 这里他把对象 销毁再创建 但是由于我只想刷新我自己的类 这里却把所有带ConfigurationProperties注解的都销毁重新创建
// 这样就很难以让我们采用这种方式
if (this.applicationContext != null) {
try {
Object bean = this.applicationContext.getBean(name);
if (AopUtils.isAopProxy(bean)) {
bean = ProxyUtils.getTargetObject(bean);
}
if (bean != null) {
this.applicationContext.getAutowireCapableBeanFactory()
.destroyBean(bean);
this.applicationContext.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;
}
@ManagedAttribute
public Set<String> getBeanNames() {
return new HashSet<>(this.beans.getBeanNames());
}
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
if (this.applicationContext.equals(event.getSource())
// Backwards compatible
|| event.getKeys().equals(event.getSource())) {
rebind();
}
}
}