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

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

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

1. 源码环境准备

GitHub地址:https://github.com/apolloconfig/apollo
IDEA搭建的源码环境如下:
在这里插入图片描述

我们的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配置文件
    在这里插入图片描述
  • ApolloAutoConfiguration
    在这里插入图片描述
  • ConfigPropertySourcesProcessor
    在这里插入图片描述
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
    在这里插入图片描述
    这里向BeanDefinitionRegistry注册SpringValueProcessor

  • SpringValueProcessor类

在这里插入图片描述

 @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;
  }

在这里插入图片描述

@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);
    }
  }

在这里插入图片描述

  • 如果有配置改变
    配置会通知到这个类: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);
  }

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Apollo Docker Quick Start Files是用于在Docker容器中快速启动Apollo配置中心的文件集合。Apollo配置中心是携程框架部门开发的分布式配置管理平台,用于实现配置集中管理和动态配置更新的需求。 使用Docker容器来快速启动Apollo配置中心可以提高开发和部署的效率,方便跨平台和环境的使用。Apollo Docker Quick Start Files包含了配置中心的相关配置文件、Dockerfile和启动脚本等,使用这些文件可以快速构建和启动配置中心的Docker容器。 在启动Docker容器之前,我们需要先配置Apollo配置中心的相关信息,在配置文件中指定数据库、端口等参数。然后,使用Docker命令构建Docker镜像并生成Docker容器,通过运行启动脚本,让Docker容器启动并运行Apollo配置中心。 通过使用Apollo Docker Quick Start Files,可以方便地在各种环境中部署和启动Apollo配置中心,提高系统的可维护性和可扩展性。同时,通过Docker的特性,我们可以更好地管理和监控配置中心的运行状态,更灵活地进行配置的更新和维护。 总之,Apollo Docker Quick Start Files提供了一种便捷的方式来快速部署和启动Apollo配置中心,使得我们能够更加高效地管理和使用分布式配置,提高系统的稳定性和可靠性。 ### 回答2: Apollo是一个分布式配置中心,用于管理和配置分布式系统中的应用程序的配置信息。Docker是一种容器化平台,可以将应用程序打包成容器,并在不同的环境中快速部署和运行。 Apollo-Docker-Quick-Start-Files是一个用于快速开始使用Apollo和Docker的文件集合。它包含了一系列的配置文件和脚本,可以帮助用户快速搭建Apollo配置中心和使用Docker部署应用程序。 在这个文件集合中,用户可以找到一些配置文件示例,如application.properties和meta-server.properties,这些文件定义了Apollo配置中心和元数据服务器的相关配置信息。用户可以根据自己的需要进行修改和定制。 此外,还有一些脚本文件,如docker-compose.yaml和Dockerfile。这些文件用于定义Docker容器的构建和部署规则。用户可以使用docker-compose命令,根据docker-compose.yaml文件一键启动Apollo配置中心和应用程序的Docker容器。 使用Apollo-Docker-Quick-Start-Files,用户可以轻松地搭建Apollo配置中心和部署应用程序。它提供了一种快捷的方式,帮助用户快速入门并使用Apollo和Docker进行分布式系统的配置和部署管理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值