完整的时序图
涵盖从Spring容器启动、Undertow集成、Servlet注册,到用户请求的完整生命周期
sequenceDiagram
participant U as 用户/浏览器
participant DNS as DNS服务器
participant OS as 操作系统
内核/网卡 participant UT as Undertow
I/O线程 participant WT as Undertow
工作线程 participant SCI as ServletContext-
Initializer participant DS as Dispatcher-
Servlet participant SC as Spring容器
(ApplicationContext) participant MVC as Spring MVC
组件 participant DB as 数据库 Note over U, DB: 阶段1: 应用启动阶段 rect rgb(240, 255, 240) Note over SC, SCI: 1. Spring容器启动 SC->>SC: SpringApplication.run()
创建ApplicationContext SC->>SC: 扫描@Component、@Bean等
初始化所有单例Bean SC->>DS: 创建DispatcherServlet Bean
@Bean DispatcherServlet Note over SC, SCI: 2. 自动配置机制 SC->>SCI: 创建ServletRegistrationBean
(实现ServletContextInitializer) SCI->>SCI: 包含DispatcherServlet和URL映射配置 Note over UT, SCI: 3. Undertow服务器启动 SC->>UT: 创建Undertow实例
配置I/O线程(16)和工作线程(512) UT->>UT: 绑定端口8080
启动事件监听循环 Note over UT, SCI: 4. Servlet注册回调 UT->>SCI: 回调onStartup()方法
(通过TomcatStarter桥接) SCI->>UT: 调用servletContext.addServlet()
注册DispatcherServlet到Undertow UT->>UT: 完成Servlet注册
更新URL映射表 end Note over U, DB: 阶段2: DNS解析和网络传输 rect rgb(240, 248, 255) U->>DNS: DNS查询
example.com → 192.168.1.100 DNS->>U: 返回IP地址 U->>OS: HTTP请求 GET /api/users
TCP三次握手建立连接 OS->>OS: 网卡接收数据→DMA→内核缓冲区 end Note over U, DB: 阶段3: Undertow接收和处理 rect rgb(255, 248, 240) OS->>UT: 通过epoll通知数据就绪
I/O线程从内核缓冲区读取 UT->>UT: 解析HTTP协议
创建HttpServerExchange UT->>WT: 从线程池(512)借用工作线程
传递请求信息 Note over WT, DS: 4. Servlet处理链 WT->>DS: 调用service()方法
请求进入Spring MVC世界 DS->>MVC: doDispatch()开始处理
查找HandlerMapping MVC->>MVC: 执行Interceptor.preHandle()
参数绑定验证 MVC->>SC: 调用@Controller方法
执行业务逻辑 SC->>DB: 执行SQL查询
工作线程等待数据库响应 DB->>SC: 返回查询结果 SC->>MVC: 返回ModelAndView
执行Interceptor.postHandle() MVC->>DS: 处理完成
准备响应数据 DS->>WT: 返回响应给工作线程 WT->>UT: 工作线程释放
响应数据交还I/O线程 end Note over U, DB: 阶段4: 响应返回 rect rgb(248, 240, 255) UT->>OS: I/O线程写入内核发送缓冲区 OS->>U: 操作系统组包发送HTTP响应 U->>U: 浏览器接收响应
解析HTML/JSON渲染页面 UT->>UT: 保持HTTP连接
等待下一个请求 end Note over U, DB: 阶段5: 连接管理(后续请求) U->>UT: 同一连接的后续请求
复用现有TCP连接 UT->>WT: 直接分配工作线程处理
跳过DNS和连接建立阶段
内核/网卡 participant UT as Undertow
I/O线程 participant WT as Undertow
工作线程 participant SCI as ServletContext-
Initializer participant DS as Dispatcher-
Servlet participant SC as Spring容器
(ApplicationContext) participant MVC as Spring MVC
组件 participant DB as 数据库 Note over U, DB: 阶段1: 应用启动阶段 rect rgb(240, 255, 240) Note over SC, SCI: 1. Spring容器启动 SC->>SC: SpringApplication.run()
创建ApplicationContext SC->>SC: 扫描@Component、@Bean等
初始化所有单例Bean SC->>DS: 创建DispatcherServlet Bean
@Bean DispatcherServlet Note over SC, SCI: 2. 自动配置机制 SC->>SCI: 创建ServletRegistrationBean
(实现ServletContextInitializer) SCI->>SCI: 包含DispatcherServlet和URL映射配置 Note over UT, SCI: 3. Undertow服务器启动 SC->>UT: 创建Undertow实例
配置I/O线程(16)和工作线程(512) UT->>UT: 绑定端口8080
启动事件监听循环 Note over UT, SCI: 4. Servlet注册回调 UT->>SCI: 回调onStartup()方法
(通过TomcatStarter桥接) SCI->>UT: 调用servletContext.addServlet()
注册DispatcherServlet到Undertow UT->>UT: 完成Servlet注册
更新URL映射表 end Note over U, DB: 阶段2: DNS解析和网络传输 rect rgb(240, 248, 255) U->>DNS: DNS查询
example.com → 192.168.1.100 DNS->>U: 返回IP地址 U->>OS: HTTP请求 GET /api/users
TCP三次握手建立连接 OS->>OS: 网卡接收数据→DMA→内核缓冲区 end Note over U, DB: 阶段3: Undertow接收和处理 rect rgb(255, 248, 240) OS->>UT: 通过epoll通知数据就绪
I/O线程从内核缓冲区读取 UT->>UT: 解析HTTP协议
创建HttpServerExchange UT->>WT: 从线程池(512)借用工作线程
传递请求信息 Note over WT, DS: 4. Servlet处理链 WT->>DS: 调用service()方法
请求进入Spring MVC世界 DS->>MVC: doDispatch()开始处理
查找HandlerMapping MVC->>MVC: 执行Interceptor.preHandle()
参数绑定验证 MVC->>SC: 调用@Controller方法
执行业务逻辑 SC->>DB: 执行SQL查询
工作线程等待数据库响应 DB->>SC: 返回查询结果 SC->>MVC: 返回ModelAndView
执行Interceptor.postHandle() MVC->>DS: 处理完成
准备响应数据 DS->>WT: 返回响应给工作线程 WT->>UT: 工作线程释放
响应数据交还I/O线程 end Note over U, DB: 阶段4: 响应返回 rect rgb(248, 240, 255) UT->>OS: I/O线程写入内核发送缓冲区 OS->>U: 操作系统组包发送HTTP响应 U->>U: 浏览器接收响应
解析HTML/JSON渲染页面 UT->>UT: 保持HTTP连接
等待下一个请求 end Note over U, DB: 阶段5: 连接管理(后续请求) U->>UT: 同一连接的后续请求
复用现有TCP连接 UT->>WT: 直接分配工作线程处理
跳过DNS和连接建立阶段
关键环节的详细说明
1. Spring与Undertow的集成细节(阶段1)
自动配置机制:
java
// Spring Boot自动配置类
@Configuration
@ConditionalOnClass({Servlet.class, Undertow.class})
public class UndertowServletWebServerFactoryConfiguration {
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
// 创建Undertow工厂
return new UndertowServletWebServerFactory();
}
}
// Servlet注册(关键桥梁)
@Bean
public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration() {
// 这个Bean实现了ServletContextInitializer接口
return new ServletRegistrationBean<>(dispatcherServlet(), "/");
}
Undertow启动过程:
java
// Spring Boot启动Undertow的简化流程
public class UndertowWebServer implements WebServer {
public void start() {
// 1. 创建Undertow Builder
Undertow.Builder builder = Undertow.builder()
.addHttpListener(port, "0.0.0.0")
.setIoThreads(16) // I/O线程
.setWorkerThreads(512) // 工作线程
.setHandler(handlers);
// 2. 启动服务器
this.undertow = builder.build();
this.undertow.start();
// 3. 回调ServletContextInitializer
for (ServletContextInitializer initializer : initializers) {
initializer.onStartup(this.getServletContext());
}
}
}
2. 请求处理链的详细流程(阶段3)
Undertow → Spring MVC的转换:
java
// Undertow的HttpHandler处理请求
public class ServletInitialHandler implements HttpHandler {
public void handleRequest(HttpServerExchange exchange) {
// 1. 将Undertow的Exchange转换为Servlet的Request/Response
ServletRequestContext servletRequestContext =
new ServletRequestContext(exchange, servletContext);
HttpServletRequest request = servletRequestContext.getServletRequest();
HttpServletResponse response = servletRequestContext.getServletResponse();
// 2. 创建Filter链并执行
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
// 3. 最终调用DispatcherServlet.service()
filterChain.doFilter(request, response);
}
}
Spring MVC内部处理:
java
// DispatcherServlet的核心处理流程
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// 1. 查找HandlerMapping
HandlerExecutionChain mappedHandler = getHandler(request);
// 2. 获取HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 执行拦截器前置处理
if (!mappedHandler.applyPreHandle(request, response)) return;
// 4. 实际执行Controller方法
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
// 5. 执行拦截器后置处理
mappedHandler.applyPostHandle(request, response, mv);
// 6. 处理结果渲染
processDispatchResult(request, response, mappedHandler, mv, null);
}
3. 网络层面的细节(阶段2和4)
DNS解析过程:
- 浏览器缓存检查 → 2. 系统缓存检查 → 3. 路由器缓存检查 → 4. ISP DNS缓存 → 5. 递归查询 → 6. 返回IP地址
TCP连接复用:
- 建立连接后,后续请求复用同一连接
- 第一次请求: TCP握手 → HTTP请求/响应
- 第二次请求: HTTP请求/响应(复用连接)
- 第三次请求: HTTP请求/响应(复用连接)
4. 线程模型的关键点
Undertow的两级线程池:
- I/O线程(16个) :非阻塞处理网络I/O,不执行业务逻辑
- 工作线程(512个) :阻塞式处理业务逻辑,可被挂起等待IO
优势: 工作线程在等待数据库时可以处理其他请求
- 工作线程1: 开始处理请求A → 等待数据库 → 挂起
- 工作线程1: 被唤醒处理请求B → 快速计算 → 返回响应
- 工作线程1: 数据库响应到达 → 继续处理请求A → 返回响应
完整数据流总结
- 启动阶段:Spring容器 → 创建Bean → 启动Undertow → 注册Servlet
- 请求接收:DNS解析 → 建立TCP连接 → 内核接收 → Undertow I/O线程
- 业务处理:工作线程 → DispatcherServlet → Spring MVC → 业务逻辑 → 数据库
- 响应返回:处理结果 → 工作线程 → I/O线程 → 内核发送 → 网络传输 → 浏览器