springboot啓動配置文件加載過程

new SpringApplication(primarySources).run(args);

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();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
}

new SpringApplication() 後的成員變量

this.initializers = {ArrayList@1400}  size = 7
 0 = {DelegatingApplicationContextInitializer@1404} 
 1 = {SharedMetadataReaderFactoryContextInitializer@1405} 
 2 = {ContextIdApplicationContextInitializer@1406} 
 3 = {ConfigurationWarningsApplicationContextInitializer@1407} 
 4 = {RSocketPortInfoApplicationContextInitializer@1408} 
 5 = {ServerPortInfoApplicationContextInitializer@1409} 
 6 = {ConditionEvaluationReportLoggingListener@1410} 
this.listeners = {ArrayList@1488}  size = 14
 0 = {BootstrapApplicationListener@1492} 
 1 = {LoggingSystemShutdownListener@1493} 
 2 = {CloudFoundryVcapEnvironmentPostProcessor@1494} 
 3 = {ConfigFileApplicationListener@1495} 
 4 = {AnsiOutputApplicationListener@1496} 
 5 = {LoggingApplicationListener@1497} 
 6 = {ClasspathLoggingApplicationListener@1498} 
 7 = {BackgroundPreinitializer@1499} 
 8 = {DelegatingApplicationListener@1500} 
 9 = {RestartListener@1501} 
 10 = {ParentContextCloserApplicationListener@1502} 
 11 = {ClearCachesApplicationListener@1503} 
 12 = {FileEncodingApplicationListener@1504} 
 13 = {LiquibaseServiceLocatorApplicationListener@1505} 

getRunListeners(args);

this = {SpringApplication@1272} 
listeners = {SpringApplicationRunListeners@1653}
	listeners = {ArrayList@1657}  size = 1
	0 = {EventPublishingRunListener@1659} 
		application = {SpringApplication@1272} 
		initialMulticaster = {SimpleApplicationEventMulticaster@1660} 

listeners.starting();

void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
}
this = {SpringApplicationRunListeners@1653} 
this.listeners = {ArrayList@1657}  size = 1
 0 = {EventPublishingRunListener@1659} 
	application = {SpringApplication@1272} 
	args = {String[0]@1515} 
	initialMulticaster = {SimpleApplicationEventMulticaster@1660} 

SpringApplication.run(String... args)

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

SpringApplication.prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
}

getOrCreateEnvironment();

new StandardServletEnvironment(); // 創建環境
System.getProperties();// 獲取系統屬性
System.getenv();// 系統環境

configureEnvironment(environment, applicationArguments.getSourceArgs()); // 得到spring.profiles.active參數

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
		if (this.addConversionService) {
			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
			environment.setConversionService((ConfigurableConversionService) conversionService);
		}
		configurePropertySources(environment, args);
		configureProfiles(environment, args); // 找到 spring.profiles.active 配置的參數,environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}

ConfigurationPropertySources.attach(environment);

sources增加ConfigurationPropertySourcesPropertySource {name='configurationProperties'}

environment = {StandardServletEnvironment@1898} "StandardServletEnvironment {activeProfiles=[deve], defaultProfiles=[default], propertySources=[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, StubPropertySource {name='servletConfigInitParams'}, StubPropertySource {name='servletContextInitParams'}, PropertiesPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]}"
sources = {MutablePropertySources@2125} "[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, StubPropertySource {name='servletConfigInitParams'}, StubPropertySource {name='servletContextInitParams'}, PropertiesPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]"
 propertySourceList = {CopyOnWriteArrayList@2138}  size = 5
  0 = {ConfigurationPropertySourcesPropertySource@2160} "ConfigurationPropertySourcesPropertySource {name='configurationProperties'}"
  1 = {PropertySource$StubPropertySource@2140} "StubPropertySource {name='servletConfigInitParams'}"
  2 = {PropertySource$StubPropertySource@2141} "StubPropertySource {name='servletContextInitParams'}"
  3 = {PropertiesPropertySource@2142} "PropertiesPropertySource {name='systemProperties'}"
  4 = {SystemEnvironmentPropertySource@2143} "SystemEnvironmentPropertySource {name='systemEnvironment'}"
attached = null

listeners.environmentPrepared(environment); // 遍歷Listener,執行Listener的onApplicationEvent方法

org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent[source=org.springframework.boot.SpringApplication@55b699ef]

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 {
				invokeListener(listener, event);
			}
		}
}

getApplicationListeners(event, type)

getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
listeners = {ArrayList@3901}  size = 9
 0 = {BootstrapApplicationListener@1492} 
 1 = {LoggingSystemShutdownListener@1493} 
 2 = {ConfigFileApplicationListener@1495} 
 3 = {AnsiOutputApplicationListener@1496} 
 4 = {LoggingApplicationListener@1497} 
 5 = {ClasspathLoggingApplicationListener@1498} 
 6 = {BackgroundPreinitializer@1499} 
 7 = {DelegatingApplicationListener@1500} 
 8 = {FileEncodingApplicationListener@1504} 
} 

invokeListener(listener, event);

當 listener = BootstrapApplicationListener 時,ConfigurableApplicationContext 找到默認的配置文件名 "${spring.cloud.bootstrap.name:bootstrap}"

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 context 當有bootstrap時候,不在需要初始化
		if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
			return;
		}
		ConfigurableApplicationContext context = null;
		String configName = environment
				.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
		for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
				.getInitializers()) {
			if (initializer instanceof ParentContextApplicationContextInitializer) {
				context = findBootstrapContext(
						(ParentContextApplicationContextInitializer) initializer,
						configName);
			}
		}
		if (context == null) {
			context = bootstrapServiceContext(environment, event.getSpringApplication(),
					configName);
			event.getSpringApplication()
					.addListeners(new CloseContextOnFailureApplicationListener(context));
		}

		apply(context, event.getSpringApplication(), environment);
}

初始化 bootstrapServiceContext

context = bootstrapServiceContext(environment, event.getSpringApplication(), configName);

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 it
		bootstrapMap.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);
		}
		// 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);
		final SpringApplication builderApplication = builder.application();
		if (builderApplication.getMainApplicationClass() == null) {
			// gh_425:
			// SpringApplication cannot deduce the MainApplicationClass here
			// if it is booted from SpringBootServletInitializer due to the
			// absense of the "main" method in stackTraces.
			// But luckily this method's second parameter "application" here
			// carries the real MainApplicationClass which has been explicitly
			// set by SpringBootServletInitializer itself already.
			builder.main(application.getMainApplicationClass());
		}
		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.
			builderApplication
					.setListeners(filterListeners(builderApplication.getListeners()));
		}
		builder.sources(BootstrapImportSelectorConfiguration.class);
		final ConfigurableApplicationContext context = builder.run(); // ConfigurableApplicationContext 初始化
		// 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 context
		addAncestorInitializer(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;
}

org.springframework.boot.context.event.ApplicationStartingEvent[source=org.springframework.boot.SpringApplication@4738a206]

再次run方法

當 listener = {ConfigFileApplicationListener@2387} ,真正去加載配置

private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			getSearchLocations().forEach((location) -> {
				boolean isFolder = location.endsWith("/");
				// names 第一次初始化context是bootstrap,第二次執行程序是application
				Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
				names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
			});
}
public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
}

加載文件,文件命名規則:prefix + "-" + profile + fileExtension;

private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension,
				Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null);
			DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
			if (profile != null) {
				// Try profile-specific file & profile section in profile file (gh-340)
				String profileSpecificFile = prefix + "-" + profile + fileExtension;
				load(loader, profileSpecificFile, profile, defaultFilter, consumer);
				load(loader, profileSpecificFile, profile, profileFilter, consumer);
				// Try profile specific sections in files we've already processed
				for (Profile processedProfile : this.processedProfiles) {
					if (processedProfile != null) {
						String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
						load(loader, previouslyLoaded, profile, profileFilter, consumer);
					}
				}
			}
			// Also try the profile-specific section (if any) of the normal file
			load(loader, prefix + fileExtension, profile, profileFilter, consumer);
}

總結: bootstrap文件在第一階段初始化Context時候加載 application文件在啓動應用程序時候加載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章