千家信息网

apollo在spring-boot中的加载过程是什么

发表于:2025-01-18 作者:千家信息网编辑
千家信息网最后更新 2025年01月18日,本篇内容介绍了"apollo在spring-boot中的加载过程是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读
千家信息网最后更新 2025年01月18日apollo在spring-boot中的加载过程是什么

本篇内容介绍了"apollo在spring-boot中的加载过程是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

集成使用

1、添加 gradle 依赖

    implementation "com.ctrip.framework.apollo:apollo-client:1.6.0"

2、配置 application.properties

apollo 自身的配置共包含 9 项,必要配置只有 3 项,其他的都是可选的配置。apollo 在 spring-boot 环境下的配置命名和 System 参数的命名保持了一直,最终 spring 的配置会注入到 System 中,具体的逻辑下文分析。

必须配置
#应用的IDapp.id = java-project# apollo 的 config-service 服务发现地址apollo.meta = http://apollo.meta# 启用 apolloapollo.bootstrap.enabled = true
可选配置
# 在日志系统初始化前加载 apollo 配置apollo.bootstrap.eagerLoad.enabled=true# 加载的命名空间,默认加载 application ,多个以逗号隔开apollo.bootstrap.namespaces = application# apollo 的安全拉取 secret 配置apollo.accesskey.secret = xx# 集群配置apollo.cluster = hk# 缓存路径apollo.cacheDir = /opt# 是否保持和 apollo 配置页面的配置顺序一致apollo.property.order.enable = true

加载过程解析

public class ApolloApplicationContextInitializer implements ApplicationContextInitializer , EnvironmentPostProcessor, Ordered {  public static final int DEFAULT_ORDER = 0;  private static final Logger logger = LoggerFactory.getLogger(ApolloApplicationContextInitializer.class);  private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();  private static final String[] APOLLO_SYSTEM_PROPERTIES = {"app.id", ConfigConsts.APOLLO_CLUSTER_KEY,      "apollo.cacheDir", "apollo.accesskey.secret", ConfigConsts.APOLLO_META_KEY, PropertiesFactory.APOLLO_PROPERTY_ORDER_ENABLE};  private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector.getInstance(ConfigPropertySourceFactory.class);  private int order = DEFAULT_ORDER;  @Override  public void initialize(ConfigurableApplicationContext context) {    ConfigurableEnvironment environment = context.getEnvironment();    if (!environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, Boolean.class, false)) {      logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED);      return;    }    logger.debug("Apollo bootstrap config is enabled for context {}", context);    initialize(environment);  }  /**   * Initialize Apollo Configurations Just after environment is ready.   *   * @param environment   */  protected void initialize(ConfigurableEnvironment environment) {    if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {      //already initialized      return;    }    String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);    logger.debug("Apollo bootstrap namespaces: {}", namespaces);    List namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);    CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);    for (String namespace : namespaceList) {      Config config = ConfigService.getConfig(namespace);      composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));    }    environment.getPropertySources().addFirst(composite);  }  /**   * To fill system properties from environment config   */  void initializeSystemProperty(ConfigurableEnvironment environment) {    for (String propertyName : APOLLO_SYSTEM_PROPERTIES) {      fillSystemPropertyFromEnvironment(environment, propertyName);    }  }  private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environment, String propertyName) {    if (System.getProperty(propertyName) != null) {      return;    }    String propertyValue = environment.getProperty(propertyName);    if (Strings.isNullOrEmpty(propertyValue)) {      return;    }    System.setProperty(propertyName, propertyValue);  }  /**   *   * In order to load Apollo configurations as early as even before Spring loading logging system phase,   * this EnvironmentPostProcessor can be called Just After ConfigFileApplicationListener has succeeded.   *   * 
* The processing sequence would be like this:
* Load Bootstrap properties and application properties -----> load Apollo configuration properties ----> Initialize Logging systems * * @param configurableEnvironment * @param springApplication */ @Override 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) { initialize(configurableEnvironment); } } /** * @since 1.3.0 */ @Override public int getOrder() { return order; } /** * @since 1.3.0 */ public void setOrder(int order) { this.order = order; }}

apollo 在 spring-boot 中的加载逻辑都在如上的代码中了,代码的关键是实现了两个 spring 生命周期的接口,

  • ApplicationContextInitializer

在被 ConfigurableApplicationContext.refresh()刷新之前初始化 ConfigurableApplicationContext 的回调接口。

  • EnvironmentPostProcessor

比 ApplicationContextInitializer 的加载时机还要提前,此时 spring-boot 的日志系统还未初始化,

postProcessEnvironment 方法逻辑解析

  • 1、初始化 System 的配置,将 spring 上下文中的配置(环境变量、System 参数、application.properties) 拷贝到 System 配置中, 如果 System 已经存在同名的配置则跳过,保证了 -D 设置的 System 参数的最高优先级。但是也带来了一个隐含的问题,默认,apollo 的配置设计支持从环境变量中取值,也遵循了环境变量大写的规范,将 System 参数的 "." 换成 "_" 拼接,然后变成大写。 比如 apollo.meta 对应环境变量的 APOLLO_META。但是在 spring-boot 的环境下,因为 spring 的配置系统默认也会加载环境变量的配置,最终在环境变量里配置 apollo.meta 也会生效。甚至比正确配置的 APOLLO_META 环境变量值的优先级还高。

  • 2、根据 apollo.bootstrap.eagerLoad.enabled 和 apollo.bootstrap.enabled 的配置来判断是否在这个阶段初始化 apollo。 postProcessEnvironment() 执行的时候, 此时日志系统并未初始化,在这个阶段加载 apollo,可以解决将日志配置托管到 apollo 里直接生效的问题。 带来的问题是, 假如在这个阶段的 apollo 加载出现问题,由于日志系统未初始化,看不到 apollo 的加载日志,不方便定位 apollo 的加载问题。 所以博主建议,如果有托管日志配置的场景,可以先不启用 apollo.bootstrap.eagerLoad.enabled 的配置,等 apollo 集成完成后在启用。

initialize 方法逻辑解析

  • 1、根据 apollo.bootstrap.enabled 的配置来判断,是否在这个阶段初始化 apollo ,如果此时 spring 上下文中已经包含了 apollo 的 PropertySources,代表 apollo 已经 初始化过,则直接 return 掉

  • 2、根据 apollo.bootstrap.namespaces 的配置,默认不配置为 "application" ,依次获取对应的 namespace 的配置, 并将配置使用 addFirst() 具有最高优先级属性源的设置方法, 添加到了 spring 的配置上下文中。这里解释了为什么 apollo 的配置的优先级最高,比 application.properties 中直接配置都要高, 这个优先级的问题会经常闹乌龙,在本地开发调试阶段,会直接在 application.properties 里调试配置,然后怎么改都不生效,因为 apollo 里 存在了同名的配置,启动的时候直接覆盖了本地的配置。博主也犯过几次这个错误

"apollo在spring-boot中的加载过程是什么"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0