文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何在Java中对Apollo配置进行更新

2023-06-06 16:53

关注

这期内容当中小编将会给大家带来有关如何在Java中对Apollo配置进行更新,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

Java可以用来干什么

Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4. 网页开发;5. 企业级应用开发;6. Java大数据开发;7.游戏开发等。

更新流程

在 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.typeConverterHasConvertIfNecessaryWithFieldParameter = 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);  } }  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 关联起来

在 Spring 常见配置包括 2 种

public class ApiConfig {  // 1. 直接在 Field 是进行注入  @Value("${feifei.appId}")  protected String appId;  protected String predUrl; // 2. 在方法上进行注入  @Value("${predUrl}")  public void setPredUrl(String predUrl) {    this.predUrl = predUrl;  }}

在 Apollo 代码中,通过实现 BeanPostProcessor 接口来检测所有的Spring Bean 的创建过程,在 Spring Bean 创建的过程中会调用对应的 org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization 方法。

Apollo 通过在 Bean 生成过程中,检测 Bean 类中属性和方法是否存在 @Value 注解,如果存在,提出其中的 key, 其处理方法在 processFieldprocessMethod 分别处理 Field 和 Method 中可能出现的 @Value 注解。如果存在注解则将对应的信息存到 SpringValue 对应 springValueRegistry 全局对象中,方便在其它地方可以直接获取。

在属性除了通过 @Value 注入,也可以用过 xml 进行配置,在这种情况通过 processBeanPropertyValues 方法来处理

通过两种处理方式就可以将 key 和对应的 Spring Bean 信息关联起来

public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor, BeanFactoryAware { private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class); private final ConfigUtil configUtil; private final PlaceholderHelper placeholderHelper; private final SpringValueRegistry springValueRegistry; private BeanFactory beanFactory; private Multimap<String, SpringValueDefinition> beanName2SpringValueDefinitions; public SpringValueProcessor() {  configUtil = ApolloInjector.getInstance(ConfigUtil.class);  placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class);  springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class);  beanName2SpringValueDefinitions = LinkedListMultimap.create(); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)   throws BeansException {  if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && beanFactory instanceof BeanDefinitionRegistry) {   beanName2SpringValueDefinitions = SpringValueDefinitionProcessor     .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory);  } } @Override public Object postProcessBeforeInitialization(Object bean, String beanName)   throws BeansException {  if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {   super.postProcessBeforeInitialization(bean, beanName);   processBeanPropertyValues(bean, beanName);  }  return bean; } @Override protected void processField(Object bean, String beanName, Field field) {  // register @Value on field  Value value = field.getAnnotation(Value.class);  if (value == null) {   return;  }  Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());  if (keys.isEmpty()) {   return;  }  for (String key : keys) {   SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false);   springValueRegistry.register(beanFactory, key, springValue);   logger.debug("Monitoring {}", springValue);  } } @Override protected void processMethod(Object bean, String beanName, Method method) {  //register @Value on method  Value value = method.getAnnotation(Value.class);  if (value == null) {   return;  }  //skip Configuration bean methods  if (method.getAnnotation(Bean.class) != null) {   return;  }  if (method.getParameterTypes().length != 1) {   logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters",     bean.getClass().getName(), method.getName(), method.getParameterTypes().length);   return;  }  Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());  if (keys.isEmpty()) {   return;  }  for (String key : keys) {   SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);   springValueRegistry.register(beanFactory, key, springValue);   logger.info("Monitoring {}", springValue);  } } private void processBeanPropertyValues(Object bean, String beanName) {  Collection<SpringValueDefinition> propertySpringValues = beanName2SpringValueDefinitions    .get(beanName);  if (propertySpringValues == null || propertySpringValues.isEmpty()) {   return;  }  for (SpringValueDefinition definition : propertySpringValues) {   try {    PropertyDescriptor pd = BeanUtils      .getPropertyDescriptor(bean.getClass(), definition.getPropertyName());    Method method = pd.getWriteMethod();    if (method == null) {     continue;    }    SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(),      bean, beanName, method, false);    springValueRegistry.register(beanFactory, definition.getKey(), springValue);    logger.debug("Monitoring {}", springValue);   } catch (Throwable ex) {    logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(),      definition.getPropertyName());   }  }  // clear  beanName2SpringValueDefinitions.removeAll(beanName); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException {  this.beanFactory = beanFactory; }}

上述就是小编为大家分享的如何在Java中对Apollo配置进行更新了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯