在我的上一篇博客中簡單記錄了SpringBoot
中嵌入式Servlet容器是如何實現自動配置的,並且如何讀取我們自己編寫的Customizer,這一篇博客來介紹一下這個嵌入式Servlet容器是如何啓動的,並且聯動之前的博客,來說明一下整個SpringBoot
項目是如何跑起來的。
這一篇博客與上一篇嵌入式自動配置的博客關係比較大,合起來可以大致明白整個SpringBoot
項目的嵌入式Servlet容器的啓動原理和自動配置生效原理,大家如果感興趣的話可以翻看一下我之前的博客哦。接下來進入正題。
Springboot
項目要啓動,那就要運行主程序類中的run()
方法,我們點進去看一下,裏面有幾個方法值得關注:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
createApplicationContext:觀看它的源碼,可以看到裏面有個switch語句,裏面根據當前應用是什麼類型,而來創建什麼樣的IOC容器,如果是web應用,則創建AnnotationConfigServletWebServerApplicationContext類型的IOC容器,反之則創建AnnotationConfigApplicationContext類型的IOC容器
在run方法內還有一個方法:refreshContext(context)
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
}
該方法的作用是創建IOC容器對象,並初始化容器,創建容器中的每一個組件
再點進去,發現refresh方法,它是一個接口
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();
}
}
}
裏面有一個onfresh()方法,那麼就要去找它的實現類了,這個實現類其實就是我們剛剛創建的web應用的IOC容器,它重寫了onfresh()方法。這裏其實就是個面向接口編程的思想,如果當前不是web應用,那麼它就執行默認的ioc容器內的onfresh方法
而webioc容器內部會創建嵌入式的Servlet容器createEmbeddedServletContainer();
又在這個方法的內部有一行:
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
看方法名,可以得出,獲取嵌入式的Servlet容器工廠。它是直接從容器中獲取對象,之後的步驟就和之前的博客連接起來了,這裏以tomcat爲例,SpringBoot
會根據引入的依賴從而選擇Tomcat的嵌入式工廠,並把它放到容器中。上文提到的後置處理器一看是這個對象,就獲取所有的定製器來先定製Servlet容器的相關配置;
之後會執行到這條語句
this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());
調用工廠中的方法,從而獲取到嵌入式Servlet容器。
最終嵌入式的Servlet容器創建對象並啓動Servlet容器。
之後refresh方法會繼續執行,再將IOC容器中的其他組件創建出來。