欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring?boot微服務(wù)場(chǎng)景下apollo加載過(guò)程解析

 更新時(shí)間:2022年02月21日 11:34:50   作者:kl  
apollo?是一個(gè)開(kāi)源的配置中心項(xiàng)目,功能很強(qiáng)大,apollo?本身的配置項(xiàng)并不復(fù)雜,但是因?yàn)榕渲玫穆窂教貏e多,非常容易搞混了,?所以本文試圖聚焦?spring-boot?的場(chǎng)景,在?spring-boot?微服務(wù)場(chǎng)景下,搞清楚?apollo-client的加載過(guò)程

集成使用

1、添加 gradle 依賴

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

2、配置 application.properties

apollo 自身的配置共包含 9 項(xiàng),必要配置只有 3 項(xiàng),其他的都是可選的配置。apollo 在 spring-boot 環(huán)境下的配置命名和 System 參數(shù)的命名保持了一直,最終 spring 的配置會(huì)注入到 System 中,具體的邏輯下文分析。

必須配置

#應(yīng)用的ID
app.id = java-project
# apollo 的 config-service 服務(wù)發(fā)現(xiàn)地址
apollo.meta = http://apollo.meta
# 啟用 apollo
apollo.bootstrap.enabled = true

可選配置

# 在日志系統(tǒng)初始化前加載 apollo 配置
apollo.bootstrap.eagerLoad.enabled=true
# 加載的命名空間,默認(rèn)加載 application ,多個(gè)以逗號(hào)隔開(kāi)
apollo.bootstrap.namespaces = application
# apollo 的安全拉取 secret 配置
apollo.accesskey.secret = xx
# 集群配置
apollo.cluster = hk
# 緩存路徑
apollo.cacheDir = /opt
# 是否保持和 apollo 配置頁(yè)面的配置順序一致
apollo.property.order.enable = true

加載過(guò)程解析

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);
    ListnamespaceList = 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 中的加載邏輯都在如上的代碼中了,代碼的關(guān)鍵是實(shí)現(xiàn)了兩個(gè) spring 生命周期的接口,

  • ApplicationContextInitializer

在被 ConfigurableApplicationContext.refresh()刷新之前初始化 ConfigurableApplicationContext 的回調(diào)接口。

  • EnvironmentPostProcessor

比 ApplicationContextInitializer 的加載時(shí)機(jī)還要提前,此時(shí) spring-boot 的日志系統(tǒng)還未初始化,

postProcessEnvironment 方法邏輯解析

1、初始化 System 的配置,將 spring 上下文中的配置(環(huán)境變量、System 參數(shù)、application.properties) 拷貝到 System 配置中, 如果 System 已經(jīng)存在同名的配置則跳過(guò),保證了 -D 設(shè)置的 System 參數(shù)的最高優(yōu)先級(jí)。但是也帶來(lái)了一個(gè)隱含的問(wèn)題,默認(rèn),apollo 的配置設(shè)計(jì)支持從環(huán)境變量中取值,也遵循了環(huán)境變量大寫(xiě)的規(guī)范,將 System 參數(shù)的 "." 換成 "_" 拼接,然后變成大寫(xiě)。 比如 apollo.meta 對(duì)應(yīng)環(huán)境變量的 APOLLO_META。但是在 spring-boot 的環(huán)境下,因?yàn)?spring 的配置系統(tǒng)默認(rèn)也會(huì)加載環(huán)境變量的配置,最終在環(huán)境變量里配置 apollo.meta 也會(huì)生效。甚至比正確配置的 APOLLO_META 環(huán)境變量值的優(yōu)先級(jí)還高。

2、根據(jù) apollo.bootstrap.eagerLoad.enabled 和 apollo.bootstrap.enabled 的配置來(lái)判斷是否在這個(gè)階段初始化 apollo。 postProcessEnvironment() 執(zhí)行的時(shí)候, 此時(shí)日志系統(tǒng)并未初始化,在這個(gè)階段加載 apollo,可以解決將日志配置托管到 apollo 里直接生效的問(wèn)題。 帶來(lái)的問(wèn)題是, 假如在這個(gè)階段的 apollo 加載出現(xiàn)問(wèn)題,由于日志系統(tǒng)未初始化,看不到 apollo 的加載日志,不方便定位 apollo 的加載問(wèn)題。 所以博主建議,如果有托管日志配置的場(chǎng)景,可以先不啟用 apollo.bootstrap.eagerLoad.enabled 的配置,等 apollo 集成完成后在啟用。
 

initialize 方法邏輯解析

1、根據(jù) apollo.bootstrap.enabled 的配置來(lái)判斷,是否在這個(gè)階段初始化 apollo ,如果此時(shí) spring 上下文中已經(jīng)包含了 apollo 的 PropertySources,代表 apollo 已經(jīng) 初始化過(guò),則直接 return 掉

2、根據(jù) apollo.bootstrap.namespaces 的配置,默認(rèn)不配置為 "application" ,依次獲取對(duì)應(yīng)的 namespace 的配置, 并將配置使用 addFirst() 具有最高優(yōu)先級(jí)屬性源的設(shè)置方法, 添加到了 spring 的配置上下文中。這里解釋了為什么 apollo 的配置的優(yōu)先級(jí)最高,比 application.properties 中直接配置都要高, 這個(gè)優(yōu)先級(jí)的問(wèn)題會(huì)經(jīng)常鬧烏龍,在本地開(kāi)發(fā)調(diào)試階段,會(huì)直接在 application.properties 里調(diào)試配置,然后怎么改都不生效,因?yàn)?apollo 里 存在了同名的配置,啟動(dòng)的時(shí)候直接覆蓋了本地的配置。博主也犯過(guò)幾次這個(gè)錯(cuò)誤

結(jié)語(yǔ)

上面列出的 9 項(xiàng) apollo 配置,只有三項(xiàng)配置(apollo.bootstrap.enabled、apollo.bootstrap.eagerLoad.enabled、apollo.bootstrap.namespaces)是在 spring-boot 啟動(dòng)過(guò)程中用到的,其他的配置都被透?jìng)鞯?System ,供 apollo 底層 sdk 使用。 基于此而發(fā)現(xiàn)了一個(gè) apollo 初始化配置時(shí)的小彩蛋,在 spring-boot 應(yīng)用里,如果使用環(huán)境變量來(lái)驅(qū)動(dòng) apollo 的配置項(xiàng),則帶 "." 風(fēng)格的配置(apollo.meta)和 "_" 風(fēng)格的大寫(xiě)配置(APOLLO_META)的效果是等價(jià)的,并且如果兩個(gè)配置同時(shí)存在環(huán)境變量中,前者的優(yōu)先級(jí)要高于后者

以上就是spring boot微服務(wù)場(chǎng)景下apollo加載過(guò)程解析的詳細(xì)內(nèi)容,更多關(guān)于spring-boot下apollo加載過(guò)程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 如何設(shè)置Spring Boot測(cè)試時(shí)的日志級(jí)別

    如何設(shè)置Spring Boot測(cè)試時(shí)的日志級(jí)別

    Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程。該框架使用了特定的方式來(lái)進(jìn)行配置,從而使開(kāi)發(fā)人員不再需要定義樣板化的配置。下面我們來(lái)一起學(xué)習(xí)一下吧
    2019-06-06
  • 詳解Java中Hibernate的基本原理

    詳解Java中Hibernate的基本原理

    持久化是將程序數(shù)據(jù)在持久狀態(tài)和瞬時(shí)狀態(tài)間轉(zhuǎn)換的機(jī)制。JDBC就是一種持久化機(jī)制。文件IO也是一種持久化機(jī)制。下面通過(guò)本文給大家介紹Java中Hibernate的基本原理,需要的朋友參考下吧
    2017-09-09
  • 詳解Java 微服務(wù)架構(gòu)

    詳解Java 微服務(wù)架構(gòu)

    這篇文章主要介紹了Java 微服務(wù)架構(gòu)的相關(guān)資料,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2021-02-02
  • Java手動(dòng)方式創(chuàng)建枚舉類示例

    Java手動(dòng)方式創(chuàng)建枚舉類示例

    這篇文章主要介紹了Java手動(dòng)方式創(chuàng)建枚舉類,結(jié)合實(shí)例形式分析了java創(chuàng)建枚舉類的方法及相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • Intellij IDEA神器居然還有這些小技巧

    Intellij IDEA神器居然還有這些小技巧

    Intellij IDEA真是越用越覺(jué)得它強(qiáng)大,它總是在我們寫(xiě)代碼的時(shí)候,不時(shí)給我們來(lái)個(gè)小驚喜,本文給大家主要介紹一些你可能不知道的但是又實(shí)用的小技巧,感興趣的朋友跟隨小編一起看看吧
    2021-01-01
  • JAVA中使用MD5加密實(shí)現(xiàn)密碼加密

    JAVA中使用MD5加密實(shí)現(xiàn)密碼加密

    本篇文章主要介紹JAVA中使用MD5加密實(shí)現(xiàn)密碼加密,很多地方都要存儲(chǔ)用戶密碼,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下
    2017-07-07
  • JAVA生成短8位UUID的實(shí)例講解

    JAVA生成短8位UUID的實(shí)例講解

    這篇文章主要介紹了JAVA生成短8位UUID的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • 基于FeignClient調(diào)用超時(shí)的處理方案

    基于FeignClient調(diào)用超時(shí)的處理方案

    這篇文章主要介紹了基于FeignClient調(diào)用超時(shí)的處理方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java編程使用Runtime和Process類運(yùn)行外部程序的方法

    Java編程使用Runtime和Process類運(yùn)行外部程序的方法

    這篇文章主要介紹了Java編程使用Runtime和Process類運(yùn)行外部程序的方法,結(jié)合實(shí)例形式分析了java使用Runtime.getRuntime().exec()方法運(yùn)行外部程序的常見(jiàn)情況與操作技巧,需要的朋友可以參考下
    2017-08-08
  • 淺談Java常見(jiàn)的排序算法

    淺談Java常見(jiàn)的排序算法

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java常見(jiàn)的排序算法展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06

最新評(píng)論