springboot 读取bootStrap.properties流程
一、bootstrap.properties其實是屬于spring-cloud的一個環(huán)境配置,示例如下
需要添加MAVEN包,否則不會加載bootStrap.properties。
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-context</artifactId><version>2.0.1.RELEASE</version> </dependency>二、bootstrap.properties文件加載是由org.springframework.cloud.bootstrap.
BootstrapApplicationListener在收到ApplicationEnvironmentPreparedEvent event進(jìn)行處理的。 public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {ConfigurableEnvironment environment = event.getEnvironment();if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,true)) {return;}// don't listen to events in a bootstrap contextif (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {return;}ConfigurableApplicationContext context = null;String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");if (context == null) {context = bootstrapServiceContext(environment, event.getSpringApplication(),configName);}apply(context, event.getSpringApplication(), environment);}?三、在bootstrapServiceContext函數(shù)中會設(shè)置環(huán)境變量屬性spring.config.name為bootStrap,然后會創(chuàng)建一個web-application-type為NULL的注解application,這個容器為springcloud生成的容器,到時會作為springboot的父容器,BEAN對象可以共享。application創(chuàng)建成功后,會合并屬性對象。
private ConfigurableApplicationContext bootstrapServiceContext(ConfigurableEnvironment environment, final SpringApplication application,String configName) {StandardEnvironment bootstrapEnvironment = new StandardEnvironment();MutablePropertySources bootstrapProperties = bootstrapEnvironment.getPropertySources();for (PropertySource<?> source : bootstrapProperties) {bootstrapProperties.remove(source.getName());}String configLocation = environment.resolvePlaceholders("${spring.cloud.bootstrap.location:}");Map<String, Object> bootstrapMap = new HashMap<>();bootstrapMap.put("spring.config.name", configName);// if an app (or test) uses spring.main.web-application-type=reactive, bootstrap will fail// force the environment to use none, because if though it is set below in the builder// the environment overrides itbootstrapMap.put("spring.main.web-application-type", "none");if (StringUtils.hasText(configLocation)) {bootstrapMap.put("spring.config.location", configLocation);}bootstrapProperties.addFirst(new MapPropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME, bootstrapMap));for (PropertySource<?> source : environment.getPropertySources()) {if (source instanceof StubPropertySource) {continue;}bootstrapProperties.addLast(source);}ClassLoader classLoader = Thread.currentThread().getContextClassLoader();// Use names and ensure unique to protect against duplicatesList<String> names = new ArrayList<>(SpringFactoriesLoader.loadFactoryNames(BootstrapConfiguration.class, classLoader));for (String name : StringUtils.commaDelimitedListToStringArray(environment.getProperty("spring.cloud.bootstrap.sources", ""))) {names.add(name);}// TODO: is it possible or sensible to share a ResourceLoader?SpringApplicationBuilder builder = new SpringApplicationBuilder().profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF).environment(bootstrapEnvironment)// Don't use the default properties in this builder.registerShutdownHook(false).logStartupInfo(false).web(WebApplicationType.NONE);if (environment.getPropertySources().contains("refreshArgs")) {// If we are doing a context refresh, really we only want to refresh the// Environment, and there are some toxic listeners (like the// LoggingApplicationListener) that affect global static state, so we need a// way to switch those off.builder.application().setListeners(filterListeners(builder.application().getListeners()));}List<Class<?>> sources = new ArrayList<>();for (String name : names) {Class<?> cls = ClassUtils.resolveClassName(name, null);try {cls.getDeclaredAnnotations();}catch (Exception e) {continue;}sources.add(cls);}AnnotationAwareOrderComparator.sort(sources);builder.sources(sources.toArray(new Class[sources.size()]));final ConfigurableApplicationContext context = builder.run();// gh-214 using spring.application.name=bootstrap to set the context id via// `ContextIdApplicationContextInitializer` prevents apps from getting the actual// spring.application.name// during the bootstrap phase.context.setId("bootstrap");// Make the bootstrap context a parent of the app contextaddAncestorInitializer(application, context);// It only has properties in it now that we don't want in the parent so remove// it (and it will be added back later)bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);return context;}?四、由于第三步創(chuàng)建了springcloud的SpringApplication,然后又調(diào)用了builder.run,所以會在新的APPLICATION中再次啟動RUN流程,會再次prepareEnviment進(jìn)行預(yù)處理環(huán)境,所以會再次觸發(fā)
ApplicationEnvironmentPreparedEvent,接下來會通知到org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent,由于上面第三步已經(jīng)把spring.config.name修改為bootStrap,所以會先讀取bootStrap.yaml的配置,跟之前搜索加載application.properties原理一致。五、在springcloud的應(yīng)用啟動完畢后,我們可以看到環(huán)境對象的資源屬性列表會添加一個屬性。ExtendedDefaultPropertySource {name='defaultProperties'}為BootstrapApplicationListener中的內(nèi)部屬性類。
?六、接下來繼續(xù)springboot的ApplicationEnvironmentPreparedEvent廣播到下一個listener,接下來會由springboot的這個事件通知到org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent,這時會去搜索加載application.properties,application-dev.properties,這個前面講過了,不再復(fù)述。
七、當(dāng)所有的配置文件加載完畢時,我們看下環(huán)境對象中的所有屬性資源列表
可以看到bootStrap的資源放在最后。從這里可以看到配置文件的優(yōu)先級。application-dev>application>bootStrap.?
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的springboot 读取bootStrap.properties流程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot 读取applica
- 下一篇: springboot 读取nacos配置