apollo在Springboot如何运行的

前言

配置中心我相信有一年开发经验的程序员都听过吧,有三年开发经验的程序100%都使用过配置中心配置吧。apollo做为常用的配置中心,你知道它的原理吗?你知道它是怎么集成到springboot的吗? 本篇文章带你了解其原理,让你也能够自定义组件。


一、apollo是如何完成初始化的,拉取配置的呢

1. apollo的初始化阶段

Springboot环境准备阶段,发布ApplicationEnvironmentPreparedEvent 事件,EnvironmentPostProcessorApplicationListener 监听到事件之后 执行 postProcessEnvironment方法。apollo 中 的初始化类 ApolloApplicationContextInitializer 就实现EnvironmentPostProcessor接口。 ApolloApplicationContextInitializer

java 复制代码
  public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) {

    // should always initialize system properties like app.id in the first place
    initializeSystemProperty(configurableEnvironment);

    Boolean eagerLoadEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, Boolean.class, false);

    //EnvironmentPostProcessor should not be triggered if you don't want Apollo Loading before Logging System Initialization
    if (!eagerLoadEnabled) {
      return;
    }

    Boolean bootstrapEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, Boolean.class, false);

    if (bootstrapEnabled) {
      DeferredLogger.enable();
      //重点实现逻辑的方法
      initialize(configurableEnvironment);
    }

  }

2.初始化RemoteConfigRepository

经过initialize()方法层层调用最后进入到RemoteConfigRepository init

java 复制代码
  public RemoteConfigRepository(String namespace) {
    m_namespace = namespace;
    m_configCache = new AtomicReference<>();
    m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
    m_httpClient = ApolloInjector.getInstance(HttpClient.class);
    m_serviceLocator = ApolloInjector.getInstance(ConfigServiceLocator.class);
    remoteConfigLongPollService = ApolloInjector.getInstance(RemoteConfigLongPollService.class);
    m_longPollServiceDto = new AtomicReference<>();
    m_remoteMessages = new AtomicReference<>();
    m_loadConfigRateLimiter = RateLimiter.create(m_configUtil.getLoadConfigQPS());
    m_configNeedForceRefresh = new AtomicBoolean(true);
    m_loadConfigFailSchedulePolicy = new ExponentialSchedulePolicy(m_configUtil.getOnErrorRetryInterval(),
        m_configUtil.getOnErrorRetryInterval() * 8);
    //下面三个方法就是拉去配置的核心代码了  
    //同步远程配置 
    this.trySync();
    //固定频率刷新、内部实现也是调用trySync()
    this.schedulePeriodicRefresh();
    //轮询访问远程配置中心,每次访问直到超时或者apollo 配置发生变化
    this.scheduleLongPollingRefresh();
  }

3.同步远程配置

AbstractConfigRepository.trySync()同步远程配置方法,方法内部主要实现逻辑在sync()中

java 复制代码
protected synchronized void sync() {
    Transaction transaction = Tracer.newTransaction("Apollo.ConfigService", "syncRemoteConfig");

    try {
      //m_configCache 
      ApolloConfig previous = m_configCache.get();
      //加载 远程 apollo config
      ApolloConfig current = loadApolloConfig();

      //reference equals means HTTP 304
      if (previous != current) {
        logger.debug("Remote Config refreshed!");
        m_configCache.set(current);
     	//getConfig 方法 将apollo配置放进 properties中
        this.fireRepositoryChange(m_namespace, this.getConfig());
      }

      if (current != null) {
        Tracer.logEvent(String.format("Apollo.Client.Configs.%s", current.getNamespaceName()),
            current.getReleaseKey());
      }

      transaction.setStatus(Transaction.SUCCESS);
    } catch (Throwable ex) {
      transaction.setStatus(ex);
      throw ex;
    } finally {
      transaction.complete();
    }
  }

private volatile AtomicReference<ApolloConfig> m_configCache; 使用了volatile 修饰,原子引用类型进行封装引用,这就是看源码的意义吧

4.发布ConfigFileChangeEvent事件

sync() 方法中的 调用fireRepositoryChange(),最后会调用到AbstractConfigFile.fireConfigChange()方法

java 复制代码
  private void fireConfigChange(final ConfigFileChangeEvent changeEvent) {
    for (final ConfigFileChangeListener listener : m_listeners) {
      m_executorService.submit(new Runnable() {
        @Override
        public void run() {
          String listenerName = listener.getClass().getName();
          Transaction transaction = Tracer.newTransaction("Apollo.ConfigFileChangeListener", listenerName);
          try {
          	//listner 是一个PropertySourcesProcessor 中的一个lambda 类,
          	//ConfigChangeListener configChangeEventPublisher = changeEvent ->
        //applicationEventPublisher.publishEvent(new ApolloConfigChangeEvent(changeEvent));
            listener.onChange(changeEvent);
            transaction.setStatus(Transaction.SUCCESS);
          } catch (Throwable ex) {
            transaction.setStatus(ex);
            Tracer.logError(ex);
            logger.error("Failed to invoke config file change listener {}", listenerName, ex);
          } finally {
            transaction.complete();
          }
        }
      });
    }
  }

因此我们可以监听ApolloConfigChangeEvent事件来监听apollo配置是否发生产变化 eg:

java 复制代码
public class ListenerApollo implements ConfigChangeListener, ApplicationListener<ApolloConfigChangeEvent> {
  @Override
  public void onChange(ConfigChangeEvent configChangeEvent) {
    //核心线程配置发生变化、重新set
    ConfigChange coreSize = configChangeEvent.getChange("threadPool.corePoolSize");
    if( coreSize!= null){
      ThreadPoolExecutor executor = SpringUtil.getBean(ThreadPoolExecutor.class);
      executor.setCorePoolSize(Integer.valueOf(coreSize.getNewValue()));
    }
  }

  @Override
  public void onApplicationEvent(ApolloConfigChangeEvent event) {
    this.onChange(event.getConfigChangeEvent());
  }
}

总结

分析apollo在Springboot启动的哪个环节被集成初始化的,以及跟了同步远程配置的逻辑,初始化时同步一次,定时同步,长轮询监听配置是否发生变化,发生变化又通知程序进行同步。并且同步后也会发布一个ApolloConfigChangeEvent事件,放开发者去监听配置变化。

相关推荐
泡海椒6 分钟前
jquick-pdf 饼图(JPie)实战:Java 生成贷款五级分类资产质量报告
后端
学长毕设1 小时前
基于SpringBoot的景点管理系统-附源码
java·spring boot·后端
sxlishaobin2 小时前
Maven Setting详解
java·学习·maven
知守观2 小时前
一个方法两个触发口:反编译 XXL-Job 后,我看清了 inner/job 子包的裸奔现状
java·spring boot·微服务
用户3126874877202 小时前
CompletableFuture 链式编排:异步编程的优雅解法
java
生锈的键盘2 小时前
从实战搞懂 Docker:一个 Python 项目的开发环境容器化笔记
后端
瑞雪兆丰年兮2 小时前
JavaWeb-day14-SpringBootWeb原理篇
java·开发语言·spring boot·spring·bean·mybatis·javaweb
神仙别闹3 小时前
基于 Java GUI 贪心策略直接搜索算法和极大极小博弈树算法的智能人机博弈五子棋游戏
java·毕业设计·gui·贪心策略·极大极小博弈树
九零HTTP3 小时前
RFC 7230 把请求行分了四种,网关只用得上两种
后端
Flynn Liang4 小时前
RAG 评估体系:黄金集、检索指标与 LLM-as-Judge 落地
java·langchain·rag·评估·langchain4j·检索指标