前一文學習了項目啓動的流程:
(一)new SpringApplication
- 配置source和web環境;
- 創建初始化構造器和應用監聽器;
- 配置應用的主方法所在類;
(二)run 第一部分
- 初始化計時、啓動上下文、設置系統參數;
- 初始化監聽器列表;
- 發佈springboot開始啓動事件(從applicationListeners中過濾出4個能監聽ApplicationStartingEvent事件的,並啓動它們)
繼續下面的學習這個方法:
public ConfigurableApplicationContext run(String... args) {
//1、StopWatch簡單的看成一個stop watch的機制,保存stop的記錄信息。
//初始化一個計時器,並開始計時
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//初始化啓動上下文
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
//2、configureHeadlessProperty即配置headless模式,這種模式是一種系統缺少顯示設備、鍵盤和鼠標外設的情況模式。
this.configureHeadlessProperty();
//3、SpringApplicationListeners爲SpringApplicationRunListener接口實現集合(創建SpringApplicationRunListener初始化構造器)初始化監聽器列表
//可以理解這個接口就是在spring啓動整個過程都需要回調這些listener
//debug能發現,拿到了一個名爲EventPublishingRunListener(RunListener構造方法中關聯上了全部applicationListener),這個就是用來進行觸發publishEvent的被觀察者
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//啓動EventPublishingRunListener,從而過濾並啓動相關Listener
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//4、ConfigurableEnvironment爲配置環境對象,簡單理解所有的配置信息彙總在這個對象中
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//5、Banner就是我們常在控制檯輸出的畫面橫幅,可以使用圖片或者文本進行替換
Banner printedBanner = this.printBanner(environment);
//6、ConfigurableApplicationContext根據webApp…Type進行構造的上下文對象
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//7、接下來進入關鍵步驟的第一步:prepareContext,準備容器階段,將執行所有的initializers邏輯,做初始化準備操作。
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//8、refreshContext,可以理解成容器初始化節點,將執行bean的創建和實例化。
this.refreshContext(context);
//9、afterRefresh,容器後處理, 可以看到會找到ApplicationRunner和CommandLineRunner的實現類並執行。但從2.x版本來看,似乎這個方法是個空方法,applicationRun和commandRun移到啓動最後。
this.afterRefresh(context, applicationArguments);
//10、然後根據stopwatch打印出啓動時間
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
//11、這裏調用ApplicationRunner和CommandLineRunner的實現類
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
回到正題,繼續run方法的第二部分try部分:(當前以最新SpringbootV2.4.4版本進行學習)
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//4、ConfigurableEnvironment爲配置環境對象,簡單理解所有的配置信息彙總在這個對象中
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
args參數在啓動程序時是可配置的,不配置爲null,下面跟進一下方法(將深入方法揉到一起)簡單命令行解析器解析參數,最後以PropertySource對象形式賦值給source。DefaultApplicationArguments就是保存了兩種形式的參數值
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new DefaultApplicationArguments.Source(args);
this.args = args;
}
/**
*跟進source構造方法
**/
private static class Source extends SimpleCommandLinePropertySource {
Source(String[] args) {
super(args);
}
... ...
}
/**
*跟進父類構造方法,將處理結果賦值給父類,即PropertySource對象
**/
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {
public SimpleCommandLinePropertySource(String... args) {
super((new SimpleCommandLineArgsParser()).parse(args));
}
... ...
}
/**
*跟進parse方法(命令行解析器,將啓動參數字符串截取出key與value)
**/
public CommandLineArgs parse(String... args) {
CommandLineArgs commandLineArgs = new CommandLineArgs();
String[] var3 = args;
int var4 = args.length;
for(int var5 = 0; var5 < var4; ++var5) {
String arg = var3[var5];
if (arg.startsWith("--")) {
String optionText = arg.substring(2);
String optionValue = null;
int indexOfEqualsSign = optionText.indexOf(61);
String optionName;
if (indexOfEqualsSign > -1) {
optionName = optionText.substring(0, indexOfEqualsSign);
optionValue = optionText.substring(indexOfEqualsSign + 1);
} else {
optionName = optionText;
}
if (optionName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
commandLineArgs.addOptionArg(optionName, optionValue);
} else {
commandLineArgs.addNonOptionArg(arg);
}
}
return commandLineArgs;
}
下面執行 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);逐行來看
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
====> ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
} else {
switch(this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
}
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
public StandardServletEnvironment() {
}
protected StandardServletEnvironment(MutablePropertySources propertySources) {
super(propertySources);
}
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
super.customizePropertySources(propertySources);
}
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}
}
/**
*調用父類customizeProperty方法
**/
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
}
下面來看下propertySources對象是怎麼保存的,原來是用list保存了PropertySource對象(StandardEnvironment的customizePropertiesSources中加入systemEnvironment和systemProperties,StandardServletEnvironment的customizePropertiesSources中加入servletContextInitParams和servletConfigInitParams)
public class MutablePropertySources implements PropertySources {
private final List<PropertySource<?>> propertySourceList;
public MutablePropertySources() {
this.propertySourceList = new CopyOnWriteArrayList();
}
... ...
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
====> this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
//ConversionService在前面Listener有執行過初始化(上一章節),此時爲true加載到容器中
//包含一些基本類型的轉換等,都放到environment中
if (this.addConversionService) {
// 加載一些轉換器和格式化器,下面跟進代碼
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService)conversionService);
}
//配置屬性(defaultProperties和commandLineProperties兩部分)
this.configurePropertySources(environment, args);
//內容空,之前版本是加載spring.profile.active配置的(應該是版本導致不在這裏處理了)
this.configureProfiles(environment, args);
}
public static ConversionService getSharedInstance() {
ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
if (sharedInstance == null) {
Class var1 = ApplicationConversionService.class;
synchronized(ApplicationConversionService.class) {
sharedInstance = ApplicationConversionService.sharedInstance;
if (sharedInstance == null) {
sharedInstance = new ApplicationConversionService();
ApplicationConversionService.sharedInstance = sharedInstance;
}
}
}
return sharedInstance;
}
public ApplicationConversionService(){
... ...
configure(this);
}
public static void configure(FormatterRegistry registry) {
DefaultConversionService.addDefaultConverters(registry);
DefaultFormattingConversionService.addDefaultFormatters(registry);
addApplicationFormatters(registry);
addApplicationConverters(registry);
}
public static void addApplicationConverters(ConverterRegistry registry) {
addDelimitedStringConverters(registry);
registry.addConverter(new StringToDurationConverter());
registry.addConverter(new DurationToStringConverter());
registry.addConverter(new NumberToDurationConverter());
registry.addConverter(new DurationToNumberConverter());
registry.addConverter(new StringToPeriodConverter());
registry.addConverter(new PeriodToStringConverter());
registry.addConverter(new NumberToPeriodConverter());
registry.addConverter(new StringToDataSizeConverter());
registry.addConverter(new NumberToDataSizeConverter());
registry.addConverter(new StringToFileConverter());
registry.addConverter(new InputStreamSourceToByteArrayConverter());
registry.addConverterFactory(new LenientStringToEnumConverterFactory());
registry.addConverterFactory(new LenientBooleanToEnumConverterFactory());
if (registry instanceof ConversionService) {
addApplicationConverters(registry, (ConversionService)registry);
}
}
private static void addApplicationConverters(ConverterRegistry registry, ConversionService conversionService) {
registry.addConverter(new CharSequenceToObjectConverter(conversionService));
}
public static void addDelimitedStringConverters(ConverterRegistry registry) {
ConversionService service = (ConversionService)registry;
registry.addConverter(new ArrayToDelimitedStringConverter(service));
registry.addConverter(new CollectionToDelimitedStringConverter(service));
registry.addConverter(new DelimitedStringToArrayConverter(service));
registry.addConverter(new DelimitedStringToCollectionConverter(service));
}
public static void addApplicationFormatters(FormatterRegistry registry) {
registry.addFormatter(new CharArrayFormatter());
registry.addFormatter(new InetAddressFormatter());
registry.addFormatter(new IsoOffsetFormatter());
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
====> ConfigurationPropertySources.attach((Environment)environment);
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
//檢查environment中propertySource中沒有configurationProperties,並添加configurationProperties
//如果有configurationProperties,刪除後重新添加configurationProperties
public static void attach(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
MutablePropertySources sources = ((ConfigurableEnvironment)environment).getPropertySources();
PropertySource<?> attached = sources.get("configurationProperties");
if (attached != null && attached.getSource() != sources) {
sources.remove("configurationProperties");
attached = null;
}
if (attached == null) {
sources.addFirst(new ConfigurationPropertySourcesPropertySource("configurationProperties", new SpringConfigurationPropertySources(sources)));
}
}
debug發現environment中已經包含了5個propertySource
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
====> listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
this.doWithListeners("spring.boot.application.environment-prepared", (listener) -> {
listener.environmentPrepared(bootstrapContext, environment);
});
}
此處listener還是前文提到的runListener,此處和前文過濾並執行Listener邏輯相似。下面看EventPublishingRunListener中environmentPrepared方法
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor();
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = source != null ? source.getClass() : null;
AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey);
if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
newRetriever = null;
}
}
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
if (result != null) {
return result;
}
}
return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList();
Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet() : null;
Set<String> filteredListenerBeans = retriever != null ? new LinkedHashSet() : null;
LinkedHashSet listeners;
LinkedHashSet listenerBeans;
synchronized(this.defaultRetriever) {
listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
}
Iterator var9 = listeners.iterator();
while(var9.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var9.next();
if (this.supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = this.getBeanFactory();
Iterator var16 = listenerBeans.iterator();
while(var16.hasNext()) {
String listenerBeanName = (String)var16.next();
try {
if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
filteredListeners.add(listener);
} else {
filteredListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
} else {
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
filteredListeners.remove(listener);
}
allListeners.remove(listener);
}
} catch (NoSuchBeanDefinitionException var13) {
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null) {
if (filteredListenerBeans.isEmpty()) {
retriever.applicationListeners = new LinkedHashSet(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
} else {
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
return allListeners;
}
最後得到事件監聽器有6個,並開始執行invokeListener方法(即執行listener監聽事件方法onApplicationEvent)
// 看一下EnvironmentPostProcessorApplicationListener
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
}
if (event instanceof ApplicationPreparedEvent) {
this.onApplicationPreparedEvent((ApplicationPreparedEvent)event);
}
if (event instanceof ApplicationFailedEvent) {
this.onApplicationFailedEvent((ApplicationFailedEvent)event);
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
SpringApplication application = event.getSpringApplication();
// getEnvironmentPostProcessors返回全部環境後置處理器(spring.factories中獲取)
Iterator var4 = this.getEnvironmentPostProcessors(event.getBootstrapContext()).iterator();
while(var4.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var4.next();
postProcessor.postProcessEnvironment(environment, application);
}
}
debug發現EnvironmentPostProcessorApplicationListener中ConfigDataEnvironmentPostProcessor就將spring.profile.active值配置給了參數environment.activeProfiles,方便後續加載activeProfiles裏的內容。剛剛未做任何處理的空方法this.configureProfiles(environment, args),在新版中方法內容遷移到了後置處理器中去處理了。也在這裏更新了propertyList[8個值]。其他監聽器及後置處理器不再贅述。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
====> DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
public static void moveToEnd(ConfigurableEnvironment environment) {
moveToEnd(environment.getPropertySources());
}
// 去除environment.propertySources[list|5個值]中defaultProperties
public static void moveToEnd(MutablePropertySources propertySources) {
PropertySource<?> propertySource = propertySources.remove("defaultProperties");
if (propertySource != null) {
propertySources.addLast(propertySource);
}
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
====> this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
這裏檢查additionalProfiles是否已經加載過了profiles,前面已經加載了,繼續向下執行,將環境綁定到application中,環境變量類型校驗與轉換,最後經轉換後防止丟配置進行環境對象刷新(重置environment.propertySource[list0]的configurationProperties)
進入run方法的主流程 this.configureIgnoreBeanInfo(environment);
配置忽略某些bean,配置後可以debug到下圖
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty("spring.beaninfo.ignore") == null) {
Boolean ignore = (Boolean)environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
System.setProperty("spring.beaninfo.ignore", ignore.toString());
}
}
進入run方法的主流程 Banner printedBanner = this.printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) { if (this.bannerMode == Mode.OFF) { return null; } else { ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader((ClassLoader)null); SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter((ResourceLoader)resourceLoader, this.banner); return this.bannerMode == Mode.LOG ? bannerPrinter.print(environment, this.mainApplicationClass, logger) : bannerPrinter.print(environment, this.mainApplicationClass, System.out); } }
彙總一下:
(一)new SpringApplication
- 配置source和web環境;
- 創建初始化構造器和應用監聽器;
- 配置應用的主方法所在類;
(二)run 第一二部分
- 初始化計時stopWatch、啓動上下文bootstrapContext、設置系統參數headless;
- 初始化監聽器列表SpringApplicationRunListeners;
- 發佈springboot開始啓動事件(從applicationListeners中過濾出4個能監聽ApplicationStartingEvent事件的,並啓動它們)
- 裝配命令行參數applicationArguments(對象中裝載4個propertySource);
- 準備應用程序運行的環境ConfigurableEnvironment(從applicationListeners中過濾出6個能監聽ApplicationEnvironmentPreparedEvent事件的,並啓動它們。監聽器中關聯啓動了一些後置處理器處理數據,最終目的是爲應用環境做準備)
- 配置忽略bean和打印banner
----紅色部分爲本節內容----