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文件在啓動應用程序時候加載