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>
它會自動導入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)類。此處我們先打個標記,后面我們會說下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);
????????????//準備環(huán)境信息(讀取應(yīng)用系統(tǒng)需要的所有配置項)
????????????ConfigurableEnvironment?environment?=?prepareEnvironment(listeners,?bootstrapContext,?applicationArguments);
????????????configureIgnoreBeanInfo(environment);
????????????Banner?printedBanner?=?printBanner(environment);
????????????context?=?createApplicationContext();
????????????context.setApplicationStartup(this.applicationStartup);
????????????//準備容器上下文
????????????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)境信息已準備好,觸發(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)
當執(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事件進行廣播。
//另外此處要先說明下:當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);
????????}
????????。。省略部分代碼
}此處我們假定當前的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í)行完成
此處只是做個標記,咱們繼續(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對象,當然也包括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ù)都已準備完畢,后面spring在初始化各個bean對象的時候也能根據(jù)我們在nacos上面配置的數(shù)據(jù)來創(chuàng)建各個實例對象,比如dataSource對象~
2.2.8、prepareContext方法執(zhí)行完成
到此,容器的應(yīng)用上下文都準備完畢,緊接著就會執(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-12
mybatis配置文件簡介_動力節(jié)點Java學院整理
這篇文章主要為大家詳細介紹了mybatis配置文件簡介的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
springboot+vue2+elementui實現(xiàn)時間段查詢方法
這篇文章主要介紹了springboot+vue2+elementui實現(xiàn)時間段查詢方法,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-05-05
Mybatis之類型處理器TypeHandler的作用與自定義方式
這篇文章主要介紹了Mybatis之類型處理器TypeHandler的作用與自定義方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04

