apollo动态刷新ConfigurationProperties注解标注的配置类

默认情况下 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();
  }
 }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值