您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“apollo在spring-boot中的加載過程是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
implementation "com.ctrip.framework.apollo:apollo-client:1.6.0"
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)隔開 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<ConfigurableApplicationContext> , 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<String> 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. * * <br /> * The processing sequence would be like this: <br /> * 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)還未初始化,
1、初始化 System 的配置,將 spring 上下文中的配置(環(huán)境變量、System 參數(shù)、application.properties) 拷貝到 System 配置中, 如果 System 已經(jīng)存在同名的配置則跳過,保證了 -D 設(shè)置的 System 參數(shù)的最高優(yōu)先級(jí)。但是也帶來了一個(gè)隱含的問題,默認(rèn),apollo 的配置設(shè)計(jì)支持從環(huán)境變量中取值,也遵循了環(huán)境變量大寫的規(guī)范,將 System 參數(shù)的 "." 換成 "_" 拼接,然后變成大寫。 比如 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 的配置來判斷是否在這個(gè)階段初始化 apollo。 postProcessEnvironment() 執(zhí)行的時(shí)候, 此時(shí)日志系統(tǒng)并未初始化,在這個(gè)階段加載 apollo,可以解決將日志配置托管到 apollo 里直接生效的問題。 帶來的問題是, 假如在這個(gè)階段的 apollo 加載出現(xiàn)問題,由于日志系統(tǒng)未初始化,看不到 apollo 的加載日志,不方便定位 apollo 的加載問題。 所以博主建議,如果有托管日志配置的場(chǎng)景,可以先不啟用 apollo.bootstrap.eagerLoad.enabled 的配置,等 apollo 集成完成后在啟用。
1、根據(jù) apollo.bootstrap.enabled 的配置來判斷,是否在這個(gè)階段初始化 apollo ,如果此時(shí) spring 上下文中已經(jīng)包含了 apollo 的 PropertySources,代表 apollo 已經(jīng) 初始化過,則直接 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í)的問題會(huì)經(jīng)常鬧烏龍,在本地開發(fā)調(diào)試階段,會(huì)直接在 application.properties 里調(diào)試配置,然后怎么改都不生效,因?yàn)?apollo 里 存在了同名的配置,啟動(dòng)的時(shí)候直接覆蓋了本地的配置。博主也犯過幾次這個(gè)錯(cuò)誤
“apollo在spring-boot中的加載過程是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。