携程Apollo热发布机制分析

背景

最近在使用apollo的时候,发现@Value注释的值,有部分能热更新,部分不能;对于ConfigurationProperties的配置类,完全不支持更新。所以想着了解一下apollo的热发布机制,看看是怎么实现的热发布。

官方介绍

Apollo配置中心设计
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从上面三个图可以看出:热更新,就是基于http长连接,当在apollo管理界面上修改配置时,会通知客户端有变更,然后客户端再去拉取最新的配置。

官方文档只是介绍了一下热更新机制,但是对于客户端拿到最新的配置后,怎么做到更新spring的bean的属性,却没提到。

SpringValueProcessor代码

com.ctrip.framework.apollo.spring.annotation目录下的类如下:
在这里插入图片描述
可以看到里面有一个SpringValueProcessor,从名字看,这个类的作用似乎是对spring中加了@Value注解的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 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);
    }
  }
  
  ......
  ......
  
}

SpringValueProcessor.postProcessBeforeInitialization

SpringValueProcessor重要的是postProcessBeforeInitialization方法:

@Override
  public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
   
      // 是否支持自动更新,不支持就啥事情都不做
    if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
   
      // 调用父类的postProcessBeforeInitialization
      super.postProcessBeforeInitialization(bean, beanName);
      // PropertyValues的一些处理,不需要关心
      processBeanPropertyValues(bean, beanName);
    }
    return bean;
  }

SpringValueProcessor.postProcessBeforeInitialization方法调用的是父类的postProcessBeforeInitialization方法,父类的方法内容如下:

public abstract class ApolloProcessor implements BeanPostProcessor, PriorityOrdered {
   
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
   
    Class clazz = bean.getClass();
    for (Field field : findAllField(clazz)) {
   
      processField(bean, beanName, field);
    }
    for (Method method : findAllMethod(clazz)) {
   
      processMethod(bean, beanName, method);
    }
    return bean;
  }
  
  ......
  
  protected abstract void processField(Object bean, String beanName, Field field);
  protected abstract void processMethod(Object bean, String beanName, Method method);

  ......
  
  private List<Field>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值