springboot集成nacos讀取nacos配置數(shù)據(jù)的原理
1、Nacos config springboot starter包
我們在springboot應(yīng)用中集成nacos配置中心時,添加了以下依賴:
????????<dependency> ????????????<groupId>com.alibaba.boot</groupId> ????????????<artifactId>nacos-config-spring-boot-starter</artifactId> ????????????<version>0.2.11</version> ????????</dependency>
它會自動導(dǎo)入nacos-config-spring-boot-autoconfigure包和其他nacos客戶端jar包。
看到nacos-config-spring-boot-autoconfigure這種自動配置包,我們要先打開這個jar包,看下包目錄下的/META-INF/spring.factories文件,里面有如下內(nèi)容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ ??com.alibaba.boot.nacos.config.autoconfigure.NacosConfigAutoConfiguration #org.springframework.context.ApplicationContextInitializer=\ #??com.alibaba.boot.nacos.config.autoconfigure.NacosConfigApplicationContextInitializer org.springframework.boot.env.EnvironmentPostProcessor=\ ??com.alibaba.boot.nacos.config.autoconfigure.NacosConfigEnvironmentProcessor org.springframework.context.ApplicationListener=\ ??com.alibaba.boot.nacos.config.logging.NacosLoggingListener
本次我們關(guān)注的重點是org.springframework.boot.env.EnvironmentPostProcessor這個配置項的值,它只有一個值:
com.alibaba.boot.nacos.config.autoconfigure.NacosConfigEnvironmentProcessor
我們來看下NacosConfigEnvironmentProcessor這個類,它有如下定義:
public?class?NacosConfigEnvironmentProcessor ????????implements?EnvironmentPostProcessor,?Ordered?{ ???????。。。。省略部分代碼 ????????@Override ????public?void?postProcessEnvironment(ConfigurableEnvironment?environment, ????????????SpringApplication?application)?{ ????????application.addInitializers(new?NacosConfigApplicationContextInitializer(this)); ????????nacosConfigProperties?=?NacosConfigPropertiesUtils ????????????????.buildNacosConfigProperties(environment); ????????if?(enable())?{ ????????????System.out.println( ????????????????????"[Nacos?Config?Boot]?:?The?preload?log?configuration?is?enabled"); ????????????loadConfig(environment); ????????????NacosConfigLoader?nacosConfigLoader?=?NacosConfigLoaderFactory.getSingleton(nacosConfigProperties,?environment,?builder); ????????????LogAutoFreshProcess.build(environment,?nacosConfigProperties,?nacosConfigLoader,?builder).process(); ????????} ????} }
NacosConfigEnvironmentProcessor就做了一件事,往spring容器中添加了NacosConfigApplicationContextInitializer初始化器,后續(xù)由它完成從nacos配置中心加載數(shù)據(jù)的操作。
1.1、重要的NacosConfigEnvironmentProcessor是在哪執(zhí)行的
這個問題等我們看完下面的代碼就有了答案了~
1.2、重要的NacosConfigApplicationContextInitializer是在哪執(zhí)行的
這個問題等我們看完下面的代碼也會有答案了~
2、應(yīng)用的啟動過程
我們從以下的啟動類入手。
@SpringBootApplication public?class?App?{ ????public?static?void?main(String[]?args)?{ ????????SpringApplication.run(App.class,?args); ????} }
2.1、SpringApplication的構(gòu)造方法做了啥
跟蹤上面SpringApplication的run方法,SpringApplication.run方法內(nèi)部會先創(chuàng)建一個SpringApplication對象,然后再調(diào)用該對象的另一個run實例方法。我們先進入SpringApplication的構(gòu)造方法:
public?SpringApplication(ResourceLoader?resourceLoader,?Class<?>...?primarySources)?{ ????????this.resourceLoader?=?resourceLoader; ????????Assert.notNull(primarySources,?"PrimarySources?must?not?be?null"); ????????this.primarySources?=?new?LinkedHashSet<>(Arrays.asList(primarySources)); ????????this.webApplicationType?=?WebApplicationType.deduceFromClasspath(); ????????this.bootstrapRegistryInitializers?=?new?ArrayList<>( ????????????????getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); ????????//從類路徑下面的META-INF/spring.factories文件中根據(jù)ApplicationContextInitializer配置值來初始化ApplicationContextInitializer實例 ????????setInitializers((Collection)?getSpringFactoriesInstances(ApplicationContextInitializer.class)); ????//從類路徑下面的META-INF/spring.factories文件中根據(jù)ApplicationListener配置值來初始化ApplicationListener實例 ????????setListeners((Collection)?getSpringFactoriesInstances(ApplicationListener.class)); ????????this.mainApplicationClass?=?deduceMainApplicationClass(); ????}
其中g(shù)etSpringFactoriesInstances方法用于從類路徑下面的META-INF/spring.factories文件中獲取指定配置項對應(yīng)的類的全路徑名列表(多個類的全路徑名之間用英文逗號隔開),根據(jù)類的全路徑名創(chuàng)建相應(yīng)的對象。
2.1.1、構(gòu)造方法中的setInitializers方法
setInitializers方法用于設(shè)置容器的初始化器對象集合,它的參數(shù)來源于getSpringFactoriesInstances(ApplicationContextInitializer.class)的執(zhí)行結(jié)果。getSpringFactoriesInstances方法從類路徑下面的META-INF/spring.factories文件中獲取ApplicationContextInitializer對應(yīng)的類的全路徑名列表,根據(jù)類的全路徑名創(chuàng)建相應(yīng)的對象。
2.1.2、構(gòu)造方法中的setListeners方法
setListeners方法用于設(shè)置容器的ApplicationListener監(jiān)聽器對象,它的參數(shù)來源于getSpringFactoriesInstances(ApplicationListener.class)的執(zhí)行結(jié)果。getSpringFactoriesInstances方法從類路徑下面的META-INF/spring.factories文件中獲取ApplicationListener對應(yīng)的類的全路徑名列表,根據(jù)類的全路徑名創(chuàng)建相應(yīng)的對象。spring的監(jiān)聽器就是監(jiān)聽器模式的一種實現(xiàn),它可以設(shè)置自己感興趣的事件,并且在相應(yīng)事情發(fā)生時能接到通知并對該事件進行處理。我們在spring-boot.jar包下的META-INF/spring.factories可以看到如下的內(nèi)容:
#?Application?Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
這些監(jiān)聽器類都會被實例化,并存入spring容器的ApplicationListener監(jiān)聽器列表中。
2.1.3、重要的EnvironmentPostProcessorApplicationListener出現(xiàn)了
經(jīng)過了2.1.2部分的代碼觀摩,我們知道容器的ApplicationListener監(jiān)聽器列表中已經(jīng)有了EnvironmentPostProcessorApplicationListener對象,EnvironmentPostProcessorApplicationListener很重要,它能監(jiān)聽到ApplicationEnvironmentPreparedEvent類型的事件,并且會觸發(fā)EnvironmentPostProcessor實例的執(zhí)行。我們在第1部分講到的NacosConfigEnvironmentProcessor就是個EnvironmentPostProcessor的實現(xiàn)類。此處我們先打個標(biāo)記,后面我們會說下1.1小節(jié)的NacosConfigEnvironmentProcessor實例對象是在哪執(zhí)行的。
2.2、SpringAppLication的run方法執(zhí)行流程
完成2.1節(jié)的構(gòu)造方法后,會執(zhí)行如下的run方法(本方法很重要):
????public?ConfigurableApplicationContext?run(String...?args)?{ ????????long?startTime?=?System.nanoTime(); ????????DefaultBootstrapContext?bootstrapContext?=?createBootstrapContext(); ????????ConfigurableApplicationContext?context?=?null; ????????configureHeadlessProperty(); ????????SpringApplicationRunListeners?listeners?=?getRunListeners(args); ????????listeners.starting(bootstrapContext,?this.mainApplicationClass); ????????try?{ ????????????ApplicationArguments?applicationArguments?=?new?DefaultApplicationArguments(args); ????????????//準(zhǔn)備環(huán)境信息(讀取應(yīng)用系統(tǒng)需要的所有配置項) ????????????ConfigurableEnvironment?environment?=?prepareEnvironment(listeners,?bootstrapContext,?applicationArguments); ????????????configureIgnoreBeanInfo(environment); ????????????Banner?printedBanner?=?printBanner(environment); ????????????context?=?createApplicationContext(); ????????????context.setApplicationStartup(this.applicationStartup); ????????????//準(zhǔn)備容器上下文 ????????????prepareContext(bootstrapContext,?context,?environment,?listeners,?applicationArguments,?printedBanner); ????????????//刷新容器上下文(內(nèi)部就是執(zhí)行出名的refresh方法) ????????????refreshContext(context); ????????????。。。省略部分代碼 ????????????callRunners(context,?applicationArguments); ????????} ????????。。省略部分代碼 ????????return?context; ????}
結(jié)合我們本篇要說讀取nacos配置中心的原理,本次我們主要關(guān)注getRunListeners、prepareEnvironment方法和prepareContext這三個方法,我們先按照代碼的執(zhí)行順序來依次看下這幾個方法。
2.2.1、getRunListeners方法
getRunListeners方法如下:
private?SpringApplicationRunListeners?getRunListeners(String[]?args)?{ ???Class<?>[]?types?=?new?Class<?>[]?{?SpringApplication.class,?String[].class?}; ???return?new?SpringApplicationRunListeners(logger, ?????????getSpringFactoriesInstances(SpringApplicationRunListener.class,?types,?this,?args), ?????????this.applicationStartup); }
它會讀取類路徑下面的META-INF/spring.factories文件中SpringApplicationRunListener配置項對應(yīng)的值,并創(chuàng)建相應(yīng)的實例對象,賦值給SpringApplicationRunListeners的listeners屬性(List類型),并返回SpringApplicationRunListeners對象。由于spring-boot包的META-INF/spring.factories文件有如下內(nèi)容:
#?Run?Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener
所以SpringApplicationRunListeners的listeners屬性中就包含了EventPublishingRunListener實例對象,而且實際上只有這一個對象。
2.2.2、prepareEnvironment方法開始執(zhí)行
prepareEnvironment方法內(nèi)容如下:
private?ConfigurableEnvironment?prepareEnvironment(SpringApplicationRunListeners?listeners, ????????????DefaultBootstrapContext?bootstrapContext,?ApplicationArguments?applicationArguments)?{ ????????//?Create?and?configure?the?environment ????????ConfigurableEnvironment?environment?=?getOrCreateEnvironment(); ????????configureEnvironment(environment,?applicationArguments.getSourceArgs()); ????????ConfigurationPropertySources.attach(environment); ????????//通過監(jiān)聽器通知環(huán)境信息已準(zhǔn)備好,觸發(fā)EnvironmentPostProcessor的執(zhí)行 ????????listeners.environmentPrepared(bootstrapContext,?environment); ????????DefaultPropertiesPropertySource.moveToEnd(environment); ????????Assert.state(!environment.containsProperty("spring.main.environment-prefix"), ????????????????"Environment?prefix?cannot?be?set?via?properties."); ????????bindToSpringApplication(environment); ????????if?(!this.isCustomEnvironment)?{ ????????????EnvironmentConverter?environmentConverter?=?new?EnvironmentConverter(getClassLoader()); ????????????environment?=?environmentConverter.convertEnvironmentIfNecessary(environment,?deduceEnvironmentClass()); ????????} ????????ConfigurationPropertySources.attach(environment); ????????return?environment; ????}
此處劃重點,在執(zhí)行l(wèi)isteners.environmentPrepared方法之前,我們的操作系統(tǒng)環(huán)境變量、jvm系統(tǒng)屬性和業(yè)務(wù)系統(tǒng)的application.properties(以及其他的配置文件)的配置項信息都被填充到了容器的environment對象中。
2.2.1部分的getRunListeners方法返回的SpringApplicationRunListeners對象會作為參數(shù)傳遞給prepareEnvironment方法的listeners參數(shù),而listeners.environmentPrepared就是執(zhí)行SpringApplicationRunListeners的environmentPrepared方法,方法內(nèi)容如下:
//SpringApplicationRunListeners類 void?environmentPrepared(ConfigurableBootstrapContext?bootstrapContext,?ConfigurableEnvironment?environment)?{ ????????doWithListeners("spring.boot.application.environment-prepared", ????????????????(listener)?->?listener.environmentPrepared(bootstrapContext,?environment)); ????}
里面的doWithListeners方法最后會執(zhí)行到重載的doWithListeners方法:
//SpringApplicationRunListeners類 private?void?doWithListeners(String?stepName,?Consumer<SpringApplicationRunListener>?listenerAction, ????????????Consumer<StartupStep>?stepAction)?{ ????????StartupStep?step?=?this.applicationStartup.start(stepName); ????????this.listeners.forEach(listenerAction); ????????if?(stepAction?!=?null)?{ ????????????stepAction.accept(step); ????????} ????????step.end(); ????}
前面2.2.1部分我們說了,listeners對象就是個list,此處它只有一個元素,是EventPublishingRunListener類型的實例對象。
listenerAction對象接收的是前面environmentPrepared方法內(nèi)部傳遞的lambda表達式:
(listener) -> listener.environmentPrepared(bootstrapContext, environment)
當(dāng)執(zhí)行this.listeners.forEach(listenerAction)時,就會進入EventPublishingRunListener類的environmentPrepared方法:
//EventPublishingRunListener類 public?void?environmentPrepared(ConfigurableBootstrapContext?bootstrapContext, ????????????ConfigurableEnvironment?environment)?{ ????????this.initialMulticaster.multicastEvent( ????????????????new?ApplicationEnvironmentPreparedEvent(bootstrapContext,?this.application,?this.args,?environment)); ????}
此處會調(diào)用SimpleApplicationEventMulticaster類的multicastEvent方法,并傳遞ApplicationEnvironmentPreparedEvent事件進行廣播。
//另外此處要先說明下:當(dāng)spring創(chuàng)建EventPublishingRunListener對象的時候,就已經(jīng)將SpringApplication對象的ApplicationListener對象列表添加到了EventPublishingRunListener對象的initialMulticaster屬性的監(jiān)聽器列表中,EventPublishingRunListener構(gòu)造函數(shù)代碼如下: public?EventPublishingRunListener(SpringApplication?application,?String[]?args)?{ ????????this.application?=?application; ????????this.args?=?args; ????????this.initialMulticaster?=?new?SimpleApplicationEventMulticaster(); ????????for?(ApplicationListener<?>?listener?:?application.getListeners())?{ ????????????this.initialMulticaster.addApplicationListener(listener); ????????} ????}
然后我們繼續(xù)進入SimpleApplicationEventMulticaster類的multicastEvent方法:
//SimpleApplicationEventMulticaster類 public?void?multicastEvent(final?ApplicationEvent?event,?@Nullable?ResolvableType?eventType)?{ ????????ResolvableType?type?=?(eventType?!=?null???eventType?:?resolveDefaultEventType(event)); ????????Executor?executor?=?getTaskExecutor(); ????????for?(ApplicationListener<?>?listener?:?getApplicationListeners(event,?type))?{ ????????????if?(executor?!=?null)?{ ????????????????executor.execute(()?->?invokeListener(listener,?event)); ????????????} ????????????else?{ ????????????????//會直接調(diào)用監(jiān)聽器 ????????????????invokeListener(listener,?event); ????????????} ????????} ????}
這里的getApplicationListeners(event, type)會根據(jù)事件類型獲取對該事件感興趣的監(jiān)聽器列表,然后挨個調(diào)用監(jiān)聽器對象,也就是觸發(fā)各個監(jiān)聽器的處理流程。由于此處的event參數(shù)是接收了ApplicationEnvironmentPreparedEvent對象,那么getApplicationListeners方法就會獲取到EnvironmentPostProcessorApplicationListener對象(2.1.3部分咱們提到過它)。為啥呢?我們進入EnvironmentPostProcessorApplicationListener類,它有如下的supportsEventType方法:
//EnvironmentPostProcessorApplicationListener類 @Override ????public?boolean?supportsEventType(Class<??extends?ApplicationEvent>?eventType)?{ ????????return?ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType) ????????????????||?ApplicationPreparedEvent.class.isAssignableFrom(eventType) ????????????????||?ApplicationFailedEvent.class.isAssignableFrom(eventType); ????}
supportsEventType方法就說明了該類支持處理的事件類型,里面很明確表達了它支持ApplicationEnvironmentPreparedEvent事件,所以getApplicationListeners就能把它篩選到。
我們接著上面的invokeListener方法往下看,invokeListener內(nèi)部最后會直接調(diào)用監(jiān)聽器的onApplicationEvent方法。
private?void?doInvokeListener(ApplicationListener?listener,?ApplicationEvent?event)?{ ????????try?{ ????????????listener.onApplicationEvent(event); ????????} ????????。。省略部分代碼 }
此處我們假定當(dāng)前的listener已經(jīng)是EnvironmentPostProcessorApplicationListener實例對象,那我們?nèi)タ纯碋nvironmentPostProcessorApplicationListener類的onApplicationEvent方法:
????@Override ????public?void?onApplicationEvent(ApplicationEvent?event)?{ ????????if?(event?instanceof?ApplicationEnvironmentPreparedEvent)?{ ????????????onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)?event); ????????} ????????if?(event?instanceof?ApplicationPreparedEvent)?{ ????????????onApplicationPreparedEvent(); ????????} ????????if?(event?instanceof?ApplicationFailedEvent)?{ ????????????onApplicationFailedEvent(); ????????} ????} ????private?void?onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent?event)?{ ????????ConfigurableEnvironment?environment?=?event.getEnvironment(); ????????SpringApplication?application?=?event.getSpringApplication(); ????????//重點,獲取所有的EnvironmentPostProcessor實例對象 ????????for?(EnvironmentPostProcessor?postProcessor?:?getEnvironmentPostProcessors(application.getResourceLoader(), ????????????????event.getBootstrapContext()))?{ ????????????postProcessor.postProcessEnvironment(environment,?application); ????????} ????}
上面就又出現(xiàn)了重點部分,這里會獲取所有的EnvironmentPostProcessor實例,并且挨個執(zhí)行它們的postProcessEnvironment方法,所以此時NacosConfigEnvironmentProcessor對象的postProcessEnvironment方法也就要被執(zhí)行了。
2.2.3、重要的NacosConfigEnvironmentProcessor對象終于要被執(zhí)行了
經(jīng)過了一番探索,我們在1.1小節(jié)提出的問題在此處終于有了答案~
我們來看下NacosConfigEnvironmentProcessor的postProcessEnvironment方法:
//NacosConfigEnvironmentProcessor類 @Override ????public?void?postProcessEnvironment(ConfigurableEnvironment?environment, ????????????SpringApplication?application)?{ ????????//重點,往容器中添加了NacosConfigApplicationContextInitializer對象 ????????application.addInitializers(new?NacosConfigApplicationContextInitializer(this)); ????????nacosConfigProperties?=?NacosConfigPropertiesUtils ????????????????.buildNacosConfigProperties(environment); ????????//此方法內(nèi)部邏輯可以先忽略 ????????if?(enable())?{ ????????????System.out.println( ????????????????????"[Nacos?Config?Boot]?:?The?preload?log?configuration?is?enabled"); ????????????loadConfig(environment); ????????????NacosConfigLoader?nacosConfigLoader?=?NacosConfigLoaderFactory.getSingleton(nacosConfigProperties,?environment,?builder); ????????????LogAutoFreshProcess.build(environment,?nacosConfigProperties,?nacosConfigLoader,?builder).process(); ????????} ????}
上述代碼主要就做了一件事,往spring容器中添加了NacosConfigApplicationContextInitializer初始化器。
2.2.4、NacosConfigApplicationContextInitializer終于被加入到了spring容器中
2.1.1部分我們看到spring容器中已經(jīng)有了一批ApplicationInitializer對象。剛才2.2.3部分的NacosConfigEnvironmentProcessor又往容器中添加了一個NacosConfigApplicationContextInitializer對象。這些實現(xiàn)了ApplicationInitializer接口的對象,它們會在執(zhí)行ApplicationContext的refresh方法之前得到調(diào)用。我們繼續(xù)往下看。
2.2.5、prepareEnvironment方法執(zhí)行完成
此處只是做個標(biāo)記,咱們繼續(xù)往下看~
2.2.6、prepareContext方法開始執(zhí)行
緊接著我們就來到了run方法內(nèi)部的prepareContext方法,它的內(nèi)容如下:
????private?void?prepareContext(DefaultBootstrapContext?bootstrapContext,?ConfigurableApplicationContext?context, ????????????ConfigurableEnvironment?environment,?SpringApplicationRunListeners?listeners, ????????????ApplicationArguments?applicationArguments,?Banner?printedBanner)?{ ????????context.setEnvironment(environment); ????????postProcessApplicationContext(context); ????????//執(zhí)行初始化器 ????????applyInitializers(context); ????????。。。。省略部分代碼 ?}
其中applyInitializers方法的代碼如下,它會挨個調(diào)用每個ApplicationContextInitializer實例的initialize方法,完成應(yīng)用上下文的初始化操作:
/** ?????*?Apply?any?{@link?ApplicationContextInitializer}s?to?the?context?before?it?is ?????*?refreshed. ?????*?@param?context?the?configured?ApplicationContext?(not?refreshed?yet) ?????*?@see?ConfigurableApplicationContext#refresh() ?????*/ ????@SuppressWarnings({?"rawtypes",?"unchecked"?}) ????protected?void?applyInitializers(ConfigurableApplicationContext?context)?{ ????????for?(ApplicationContextInitializer?initializer?:?getInitializers())?{ ????????????Class<?>?requiredType?=?GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ????????????????????ApplicationContextInitializer.class); ????????????Assert.isInstanceOf(requiredType,?context,?"Unable?to?call?initializer."); ????????????//執(zhí)行初始化器的初始化方法 ????????????initializer.initialize(context); ????????} ????}
我們注意到ApplicationContextInitializer實例是從getInitializers()方法獲取的,而getInitializers()方法就是返回了容器中所有的ApplicationContextInitializer對象,當(dāng)然也包括NacosConfigApplicationContextInitializer對象。
2.2.7、重要的NacosConfigApplicationContextInitializer對象終于要被執(zhí)行了
我們看下NacosConfigApplicationContextInitializer類的initialize方法:
????@Override ????public?void?initialize(ConfigurableApplicationContext?context)?{ ????????singleton.setApplicationContext(context); ????????environment?=?context.getEnvironment(); ????????nacosConfigProperties?=?NacosConfigPropertiesUtils ????????????????.buildNacosConfigProperties(environment); ????????final?NacosConfigLoader?configLoader?=?NacosConfigLoaderFactory.getSingleton( ????????????????nacosConfigProperties,?environment,?builder); ????????if?(!enable())?{ ????????????logger.info("[Nacos?Config?Boot]?:?The?preload?configuration?is?not?enabled"); ????????} ????????else?{ ????????????//?If?it?opens?the?log?level?loading?directly?will?cache ????????????//?DeferNacosPropertySource?release ????????????if?(processor.enable())?{ ????????????????processor.publishDeferService(context); ????????????????configLoader ????????????????????????.addListenerIfAutoRefreshed(processor.getDeferPropertySources()); ????????????} ????????????else?{ ????????????????//遠程訪問nacos配置中心讀取配置數(shù)據(jù) ????????????????configLoader.loadConfig(); ????????????????//設(shè)置監(jiān)聽器來監(jiān)聽nacos配置中心數(shù)據(jù)的變更并更新到本地 ????????????????configLoader.addListenerIfAutoRefreshed(); ????????????} ????????} ????????final?ConfigurableListableBeanFactory?factory?=?context.getBeanFactory(); ????????if?(!factory ????????????????.containsSingleton(NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME))?{ ????????????factory.registerSingleton(NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME, ????????????????????configLoader.getGlobalProperties()); ????????} ????}
下面展示下NacosConfigLoader類的loadConfig方法,內(nèi)部實現(xiàn)比較易懂,就是根據(jù)我們配置的nacos的訪問地址讀取指定的dataId的數(shù)據(jù),并將其封裝為一個屬性源存放到environment對象中。
//NacosConfigLoader類? public?void?loadConfig()?{ ????????MutablePropertySources?mutablePropertySources?=?environment.getPropertySources(); ????????List<NacosPropertySource>?sources?=?reqGlobalNacosConfig(globalProperties, ????????????????nacosConfigProperties.getType()); ????????for?(NacosConfigProperties.Config?config?:?nacosConfigProperties.getExtConfig())?{ ????????????List<NacosPropertySource>?elements?=?reqSubNacosConfig(config, ????????????????????globalProperties,?config.getType()); ????????????sources.addAll(elements); ????????} ???????//如果遠程nacos的配置數(shù)據(jù)比本地配置數(shù)據(jù)的優(yōu)先級高,則執(zhí)行以下方法 ????????if?(nacosConfigProperties.isRemoteFirst())?{ ????????????for?(ListIterator<NacosPropertySource>?itr?=?sources.listIterator(sources.size());?itr.hasPrevious();)?{ ????????????????//這里是個關(guān)鍵點,可以確保遠程的配置數(shù)據(jù)會被優(yōu)先使用 ????????????????mutablePropertySources.addAfter( ????????????????????????StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,?itr.previous()); ????????????} ????????}?else?{ ????????????for?(NacosPropertySource?propertySource?:?sources)?{ ????????????????mutablePropertySources.addLast(propertySource); ????????????} ????????} ????}
nacos屬性源被添加到容器的environment對象中的代碼如下:
MutablePropertySources?mutablePropertySources?=?environment.getPropertySources(); 。。。省略部分代碼 mutablePropertySources.addAfter( ????????????????????????StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,?itr.previous());
到此為止,spring啟動所需的所有的配置項數(shù)據(jù)都已準(zhǔn)備完畢,后面spring在初始化各個bean對象的時候也能根據(jù)我們在nacos上面配置的數(shù)據(jù)來創(chuàng)建各個實例對象,比如dataSource對象~
2.2.8、prepareContext方法執(zhí)行完成
到此,容器的應(yīng)用上下文都準(zhǔn)備完畢,緊接著就會執(zhí)行大名鼎鼎的refresh方法來完成spring容器的整體創(chuàng)建過程,此處就不再贅述了。
refreshContext(context);
以上就是springboot集成nacos讀取nacos配置數(shù)據(jù)的原理的詳細內(nèi)容,更多關(guān)于springboot集成nacos讀取數(shù)據(jù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
mybatis動態(tài)SQL?if的test寫法及規(guī)則詳解
這篇文章主要介紹了mybatis動態(tài)SQL?if的test寫法及規(guī)則詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01關(guān)于dubbo的RPC和RESTful性能及對比
這篇文章主要介紹了關(guān)于dubbo的RPC和RESTful性能及對比,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12mybatis配置文件簡介_動力節(jié)點Java學(xué)院整理
這篇文章主要為大家詳細介紹了mybatis配置文件簡介的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09springboot+vue2+elementui實現(xiàn)時間段查詢方法
這篇文章主要介紹了springboot+vue2+elementui實現(xiàn)時間段查詢方法,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-05-05Mybatis之類型處理器TypeHandler的作用與自定義方式
這篇文章主要介紹了Mybatis之類型處理器TypeHandler的作用與自定義方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04