本文承接上一篇文章《SpringBoot系列之嵌入式servlet容器自动配置原理》,建议结合阅读,并结合源码深入理解。
本文将探讨以下问题:
什么时候创建嵌入式的Servlet容器工厂?什么时候获取嵌入式的Servlet容器并启动Tomcat;
1)、SpringBoot应用启动运行run方法
2)、refreshContext(context);SpringBoot刷新IOC容器【创建IOC容器对象,并初始化容器,创建容器中的每一
个组件】;如果是web应用创建:AnnotationConfigEmbeddedWebApplicationContext,否则创建:AnnotationConfigApplicationContext
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
// 创建IOC容器,如果是web应用创建AnnotationConfigEmbeddedWebApplicationContext
// 否则创建AnnotationConfigApplicationContext
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 刷新IOC容器,即创建并初始化容器
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
3)、refresh(context);刷新刚才创建好的ioc容器;
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();
// SpringBoot web的ioc容器重写了onRefresh方法.
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) {
// 源码省略 ...
}
}
}
4)、onRefresh(); web的ioc容器重写了onRefresh方法
5)、webIOC容器会创建嵌入式的Servlet容器;createEmbeddedServletContainer();
6)、获取嵌入式的Servlet容器工厂:
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
从ioc容器中获取EmbeddedServletContainerFactory 组件;TomcatEmbeddedServletContainerFactory创建
对象,后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;(注:参考《SpringBoot系列之嵌入式servlet容器自动配置原理》)
7)、使用容器工厂获取嵌入式的Servlet容器:
this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());
8)、嵌入式的Servlet容器创建对象并启动Servlet容器;
先启动嵌入式的Servlet容器,再将IOC容器中剩下没有创建出的对象获取出来;IOC容器启动创建嵌入式的Servlet容器
嵌入式的Servlet容器在企业级应用中可能存在一定的局限性,使用嵌入式Servlet容器:应用需打成可执行的jar
优点:简单、便携;
缺点:默认不支持JSP、
优化定制比较复杂(使用定制器【ServerProperties、自定义EmbeddedServletContainerCustomizer】,自己编写嵌入式Servlet容器的创建工厂【EmbeddedServletContainerFactory】);
在大部分的企业应用中我们可能将项目打成war包,容器的一些参数配置到外置容器上,接下来的文章将探讨《外部Servlet容器启动SpringBoot应用》