在我的上一篇博客中简单记录了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容器中的其他组件创建出来。