從SpringBoot的主類進入SpringApplication的run()方法,然後接着往下分析
1、首先啟動一個StopWatch(秒表)
2、配置awt相關
configureHeadlessProperty();
3、從所有的jar包下的META-INF/spring.factories檔案中讀取所有的org.springframework.boot.SpringApplicationRunListener配置的類名通過反射執行個體化并儲存到SpringApplicationRunListeners的listeners(List<SpringApplicationRunListener> listeners)屬性中,并調用SpringApplicationRunListeners的starting方法,既是調用它裡面儲存的所有的SpringApplicationRunListener的starting方法。
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
4、初始化應用參數和環境變量
5、列印Banner
6、建立應用上下文ApplicationContext。根據目前應用的的類型建立不同的應用上下文,如果是web應用則建立AnnotationConfigServletWebServerApplicationContext,如果是REACTIVE反應式web應用則建立AnnotationConfigReactiveWebServerApplicationContext,否則建立基本的AnnotationConfigApplicationContext。
context = createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
7、執行一系列的前置方法prepareContext
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
8、屬性應用上下文
refreshContext(context);
執行所有的ApplicationContext的父類AbstractApplicationContext的refresh方法,重新整理Spring的IOC容器。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
如果目前是web項目,也即是ServletWebServerApplicationContext,則會調用它的onRefresh()方法,然後再調createWebServer方法,建立嵌入式web伺服器,并啟動。
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
直到最後完全啟動應用。