Apollo-配置实时生效(热发布)的原理解读

文章目录

  • 1. 源码环境准备
  • 2. 应用整合apollo方式
  • 3. 探究过程

一直很好奇spring生成的bean对象,apollo是如何修改其属性值的,比如通过 @Value注入的属性,而且还可以实时生效。 今来探究一番,只讲关键点,忽略很多细节。

前提条件,需要对spring创建bean对象过程和springboot启动有一定的了解。

1. 源码环境准备

GitHub地址:https://github.com/apolloconfig/apollo
IDEA搭建的源码环境如下:
Apollo-配置实时生效(热发布)的原理解读_第1张图片

我们的apollo服务搭建好之后,我们的应用会引入如下客户端依赖:

  <dependency>
      <groupId>com.ctrip.framework.apollo</groupId>
      <artifactId>apollo-client</artifactId>
      <version>1.9.2</version>
  </dependency>

我们要探索的就是这里。

2. 应用整合apollo方式

主要有两种方式:基于java配置,springboot集成方式。

  • 基于java配置
@Configuration
@EnableApolloConfig
public class AppConfig {
  @Bean
  public TestJavaConfigBean javaConfigBean() {
    return new TestJavaConfigBean();
  }
}
  • springboot集成方式
# will inject 'application' namespace in bootstrap phase
  apollo.bootstrap.enabled = true

这里主要介绍springboot集成方式。

3. 探究过程

  • springboot启动过程读取spring.factories配置文件
    Apollo-配置实时生效(热发布)的原理解读_第2张图片
  • ApolloAutoConfiguration
    Apollo-配置实时生效(热发布)的原理解读_第3张图片
  • ConfigPropertySourcesProcessor
    Apollo-配置实时生效(热发布)的原理解读_第4张图片
public class ConfigPropertySourcesProcessor extends PropertySourcesProcessor
    implements BeanDefinitionRegistryPostProcessor {
// 这里创建helper对象,看这个对象的代码
  private ConfigPropertySourcesProcessorHelper helper = ServiceBootstrap.loadPrimary(ConfigPropertySourcesProcessorHelper.class);

// 这里注册BeanDefinition到BeanFactory
  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    helper.postProcessBeanDefinitionRegistry(registry);
  }
}

  • ConfigPropertySourcesProcessorHelper的实现DefaultConfigPropertySourcesProcessorHelper
    Apollo-配置实时生效(热发布)的原理解读_第5张图片
    这里向BeanDefinitionRegistry注册SpringValueProcessor

  • SpringValueProcessor类

Apollo-配置实时生效(热发布)的原理解读_第6张图片

 @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
    if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
    // 看这个方法
      super.postProcessBeforeInitialization(bean, beanName);
      processBeanPropertyValues(bean, beanName);
    }
    return bean;
  }
// 在父类ApolloProcessor实现
  @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;
  }

Apollo-配置实时生效(热发布)的原理解读_第7张图片

@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注册SpringValue 
      springValueRegistry.register(beanFactory, key, springValue);
      logger.debug("Monitoring {}", springValue);
    }
  }

Apollo-配置实时生效(热发布)的原理解读_第8张图片

  • 如果有配置改变
    配置会通知到这个类:AutoUpdateConfigChangeListener
@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);
    }
  }
 public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
    if (isField()) {
      injectField(newVal);
    } else {
      injectMethod(newVal);
    }
  }
private void injectField(Object newVal) throws IllegalAccessException {
    Object bean = beanRef.get();
    if (bean == null) {
      return;
    }
    boolean accessible = field.isAccessible();
    field.setAccessible(true);
    // 通过反射方式改变值。
    field.set(bean, newVal);
    field.setAccessible(accessible);
  }

你可能感兴趣的:(Microservice,apollo)