• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Java Apollo是如何实现配置更新的

java 搞代码 4年前 (2022-01-09) 22次浏览 已收录 0个评论

这篇文档主要关注下配置修改后对应的 Java 对象是如何更新,并不关注整体的配置改动流程

所有代码都来自 apollo-client 项目

更新流程

在 Apollo 控制台进行配置修改并发布后,对应的 client 端拉取到更新后,会调用到 com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener#onChange 方法

在调用 onChange 会收到对应的修改的配置信息 ConfigChangeEvent, 其中包含改动的 key 和 value, 则改动流程如下:

  1. 根据改动的配置的 key 从 springValueRegistry 找到对应的关联到这个 key 的 Spring Bean 信息,如果找不到则不处理
  2. 根据找到的 Spring Bean 信息,进行对应关联配置的更新

在第二步中会判断关联配置是用过属性关联还是方法进行关联的,代码如下

public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
  if (isField()) {
    injectField(newVal);
  } else {
    injectMethod(newVal);
  }
}

在上面的问题中,还有两个问题存疑

  1. 如何通过 key 找到对应的 Spring Bean 信息
  2. 如何将 Apollo 的配置值转换为 Spring 的识别的值
public class AutoUpdateConfigChangeListener implements ConfigChangeListener{
 private static final Logger logger = LoggerFactory.getLogger(AutoUpdateConfigChangeListener.class);

 private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter;
 private final Environment environment;
 private final ConfigurableBeanFactory beanFactory;
 private final TypeConverter typeConverter;
 private final PlaceholderHelper placeholderHelper;
 private final SpringValueRegistry springValueRegistry;
 private final Gson gson;

 public AutoUpdateConfigChangeListener(Environment environment, ConfigurableListableBeanFactory beanFactory){
  this.typeConverterHasConvertIfNecessaryWithFieldP<mark style="color:transparent">本文来源gaodaimacom搞#^代%!码&网*</mark>arameter = testTypeConverterHasConvertIfNecessaryWithFieldParameter();
  this.beanFactory = beanFactory;
  this.typeConverter = this.beanFactory.getTypeConverter();
  this.environment = environment;
  this.placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class);
  this.springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class);
  this.gson = new Gson();
 }

 @Override
 public void onChange(ConfigChangeEvent changeEvent) {
  Set<String> keys = changeEvent.changedKeys();
  if (CollectionUtils.isEmpty(keys)) {
   return;
  }
  for (String key : keys) {
   // 1. check whether the changed key is relevant
   Collection<SpringValue> targetValues = springValueRegistry.get(beanFactory, key);
   if (targetValues == null || targetValues.isEmpty()) {
    continue;
   }

   // 2. update the value
   for (SpringValue val : targetValues) {
    updateSpringValue(val);
   }
  }
 }

 private void updateSpringValue(SpringValue springValue) {
  try {
   Object value = resolvePropertyValue(springValue);
   springValue.update(value);

   logger.info("Auto update apollo changed value successfully, new value: {}, {}", value,
     springValue);
  } catch (Throwable ex) {
   logger.error("Auto update apollo changed value failed, {}", springValue.toString(), ex);
  }
 }

 /**
  * Logic transplanted from DefaultListableBeanFactory
  * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Set, org.springframework.beans.TypeConverter)
  */
 private Object resolvePropertyValue(SpringValue springValue) {
  // value will never be null, as @Value and @ApolloJsonValue will not allow that
  Object value = placeholderHelper
    .resolvePropertyValue(beanFactory, springValue.getBeanName(), springValue.getPlaceholder());

  if (springValue.isJson()) {
   value = parseJsonValue((String)value, springValue.getGenericType());
  } else {
   if (springValue.isField()) {
    // org.springframework.beans.TypeConverter#convertIfNecessary(java.lang.Object, java.lang.Class, java.lang.reflect.Field) is available from Spring 3.2.0+
    if (typeConverterHasConvertIfNecessaryWithFieldParameter) {
     value = this.typeConverter
       .convertIfNecessary(value, springValue.getTargetType(), springValue.getField());
    } else {
     value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType());
    }
   } else {
    value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(),
      springValue.getMethodParameter());
   }
  }

  return value;
 }

 private Object parseJsonValue(String json, Type targetType) {
  try {
   return gson.fromJson(json, targetType);
  } catch (Throwable ex) {
   logger.error("Parsing json '{}' to type {} failed!", json, targetType, ex);
   throw ex;
  }
 }

 private boolean testTypeConverterHasConvertIfNecessaryWithFieldParameter() {
  try {
   TypeConverter.class.getMethod("convertIfNecessary", Object.class, Class.class, Field.class);
  } catch (Throwable ex) {
   return false;
  }
  return true;
 }
}

如何将配置 key 和 Spring Bean 关联起来


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Java Apollo是如何实现配置更新的
喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址