内嵌 Web 容器启动
内嵌 Web 容器是 Spring Boot 的核心特性,将容器启动与 Spring 生命周期集成。
容器启动时机
refresh() 流程中的容器启动
Java
public void refresh() throws BeansException {
// ...
// onRefresh() 创建 Web 容器
onRefresh();
// finishRefresh() 启动 Web 容器
finishRefresh();
}
ServletWebServerApplicationContext.onRefresh()
Java
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
} catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = null;
ServletWebServerFactory factory = getWebServerFactory();
// 创建容器(不启动)
webServer = factory.getWebServer(getSelfInitializer());
this.webServer = webServer;
initPropertySources();
}
ServletWebServerFactory
工厂接口
Java
public interface ServletWebServerFactory {
WebServer getWebServer(ServletContextInitializer... initializers);
}
Tomcat 工厂实现
Java
public class TomcatServletWebServerFactory implements ServletWebServerFactory {
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
// 1. 创建 Tomcat 实例
Tomcat tomcat = new Tomcat();
// 2. 设置基础目录
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 3. 创建 Connector
Connector connector = new Connector(this.protocol);
connector.setPort(this.port);
tomcat.getService().addConnector(connector);
// 4. 配置 Host
Host host = tomcat.getHost();
host.setAutoDeploy(false);
// 5. 创建 Context
Context context = tomcat.addContext("", baseDir.getAbsolutePath());
// 6. 配置 ServletContextInitializer
configureContext(context, initializers);
// 7. 返回 TomcatWebServer
return new TomcatWebServer(tomcat, this.port);
}
}
WebServer 实现
TomcatWebServer
Java
public class TomcatWebServer implements WebServer {
private final Tomcat tomcat;
private final int port;
@Override
public void start() throws WebServerException {
// 启动 Tomcat
this.tomcat.start();
// 等待容器就绪
awaitContainerStarted();
// 发布启动事件
publishStartedEvent();
}
@Override
public void stop() throws WebServerException {
// 停止 Tomcat
this.tomcat.stop();
}
@Override
public int getPort() {
return this.port;
}
}
UndertowWebServer
Java
public class UndertowWebServer implements WebServer {
private final Undertow.Builder builder;
@Override
public void start() throws WebServerException {
// 构建 Undertow 实例
Undertow undertow = this.builder.build();
// 启动
undertow.start();
this.undertow = undertow;
}
}
finishRefresh() 启动容器
容器启动触发
Java
protected void finishRefresh() {
super.finishRefresh();
// 启动 WebServer
WebServer webServer = startWebServer();
if (webServer != null) {
publishEvent(new WebServerInitializedEvent(webServer));
}
}
private WebServer startWebServer() {
WebServer webServer = this.webServer;
if (webServer != null) {
webServer.start();
}
return webServer;
}
ServletContextInitializer
初始化器接口
Java
public interface ServletContextInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
SelfInitializer 实现
Java
private ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
// 准备 ServletContext
prepareWebApplicationContext(servletContext);
// 注册 Servlet、Filter、Listener
registerServlets(servletContext);
registerFilters(servletContext);
registerListeners(servletContext);
}
注册 DispatcherServlet
Java
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration() {
ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>();
registration.setServlet(dispatcherServlet());
registration.addUrlMappings("/");
registration.setName("dispatcherServlet");
return registration;
}
容器自动配置
ServletWebServerFactoryAutoConfiguration
Java
@AutoConfiguration
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
public class ServletWebServerFactoryAutoConfiguration {
@Bean
@ConditionalOnClass(Tomcat.class)
public ServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
@Bean
@ConditionalOnClass(Jetty.class)
@ConditionalOnMissingBean(ServletWebServerFactory.class)
public ServletWebServerFactory jettyServletWebServerFactory() {
return new JettyServletWebServerFactory();
}
@Bean
@ConditionalOnClass(Undertow.class)
@ConditionalOnMissingBean(ServletWebServerFactory.class)
public ServletWebServerFactory undertowServletWebServerFactory() {
return new UndertowServletWebServerFactory();
}
}
启动事件
WebServerInitializedEvent
Java
public abstract class WebServerInitializedEvent extends ApplicationEvent {
private final WebServer webServer;
public WebServer getWebServer() {
return this.webServer;
}
public int getPort() {
return this.webServer.getPort();
}
}
// 具体实现
public class ServletWebServerInitializedEvent extends WebServerInitializedEvent {}
监听容器启动
Java
@Component
public class WebServerListener implements ApplicationListener<ServletWebServerInitializedEvent> {
@Override
public void onApplicationEvent(ServletWebServerInitializedEvent event) {
int port = event.getPort();
WebServer server = event.getWebServer();
System.out.println("Web容器启动完成,端口:" + port);
}
}
注意:容器在 finishRefresh() 阶段启动,此时所有 Bean 已完成初始化。
要点总结
- 容器创建在 onRefresh(),启动在 finishRefresh()
- ServletWebServerFactory 负责创建 WebServer 实例
- ServletContextInitializer 配置 Servlet/Filter
- 支持 Tomcat、Jetty、Undertow 三种容器
- WebServerInitializedEvent 通知容器启动完成
📝 发现内容有误?点击此处直接编辑