关于 SpringBoot 对嵌入式 Servlet 容器的支持
从 SpringBoot 官方文档对于嵌入式 Servlet 容器的支持 中,我们知道一下几点:
- SpringBoot 支持内嵌的
Tomcat
、Jetty
、Undertow
服务,并且提供了对应的Starter
来配置对应的实例。 - 我们可以通过使用
Spring Bean
或者扫描 Servlet 组件
的方式根据Servlet
规范来注册servlets
、filters
、listeners
。
在 Web 项目中,我们会引入 spring-boot-starter-web
这个 starter
来开启对 Web 的支持:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在 pom.xml 文件中可以看到,SpringBoot 默认使用 Tomcat 作为 Web Servlet 容器:
SpringBoot 如何集成嵌入式 Tomcat 的分析
先从程序入口 run
方法开始看,这里只分析 Tomcat 的启动流程
,关于 SpringBoot 其他组件的加载和初始化配置
请查看 SpringBoot 学习 专栏:
public ConfigurableApplicationContext run(String... args) {
...
try {
...
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 核心流程,刷新 spring 上下文
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
...
} catch (Throwable var9) {
this.handleRunFailure(context, var9, listeners);
throw new IllegalStateException(var9);
}
...
}
进入 refreshContext(context):
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
// 核心流程
this.refresh((ApplicationContext)context);
}
进入 refresh((ApplicationContext)context)
,看到在 SpringBoot 2.3.12.RELEASE
版本中这个方法加上了 @Deprecated
注解,表示在后面的版本中会替换掉这个方法
@Deprecated
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
this.refresh((ConfigurableApplicationContext)applicationContext);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
进入到 ConfigurableApplicationContext 的 refresh()
方法,有三个实现类,我们是 servlet
环境,所以看实现类 ServletWebServerApplicationContext
:
public final void refresh() throws BeansException, IllegalStateException {
try {
// 调用父类(AbstractApplicationContext)的 refresh 方法
super.refresh();
} catch (RuntimeException var3) {
WebServer webServer = this.webServer;
if (webServer != null) {
webServer.stop();
}
throw var3;
}
}
进入父类(AbstractApplicationContext)的 refresh 方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
...
// 核心流程
this.onRefresh();
...
} catch (BeansException var9) {
...
} finally {
this.resetCommonCaches();
}
}
}
onRefresh()
方法由实现类 ServletWebServerApplicationContext
提供:
protected void onRefresh() {
super.onRefresh();
try {
// 核心流程,创建 web 容器
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
// 工厂模式,获取 IoC 容器中 ServletWebServerFactory 类型的 Bean,默认使用 TomcatServletWebServerFactory
ServletWebServerFactory factory = this.getWebServerFactory();
// 核心流程
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var4) {
throw new ApplicationContextException("Cannot initialize servlet context", var4);
}
}
this.initPropertySources();
}
进入 TomcatServletWebServerFactory
的 getWebServer
方法:
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
this.customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
this.configureEngine(tomcat.getEngine());
Iterator var5 = this.additionalTomcatConnectors.iterator();
while(var5.hasNext()) {
Connector additionalConnector = (Connector)var5.next();
tomcat.getService().addConnector(additionalConnector);
}
this.prepareContext(tomcat.getHost(), initializers);
// 核心流程
return this.getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
}
调用 TomcatWebServer
的有参构造,初始化了一个 TomcatWebServer
:
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
this.monitor = new Object();
this.serviceConnectors = new HashMap();
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
// 核心流程
this.initialize();
}
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
synchronized(this.monitor) {
try {
...
// 核心流程,启动初始化好的 tomcat 实例
this.tomcat.start();
this.rethrowDeferredStartupExceptions();
...
this.startDaemonAwaitThread();
} catch (Exception var6) {
this.stopSilently();
this.destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", var6);
}
}
}
进入 Tomcat
的 start()
方法:
@Override
public final synchronized void start() throws LifecycleException {
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
}
return;
}
if (state.equals(LifecycleState.NEW)) {
// 核心流程1
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
// 核心流程2
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// This is a 'controlled' failure. The component put itself into the
// FAILED state so call stop() to complete the clean-up.
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
// This is an 'uncontrolled' failure so put the component into the
// FAILED state and throw an exception.
handleSubClassException(t, "lifecycleBase.startFail", toString());
}
}
再下面就是 Tomcat 的启动流程了,以及如何监听 HTTP 请求,这里暂时不继续分析了,后面就涉及到 Tomcat 的具体实现了。