Spring Boot + Undertow 全栈架构深度剖析时序图

完整的时序图

涵盖从Spring容器启动、Undertow集成、Servlet注册,到用户请求的完整生命周期

sequenceDiagram participant U as 用户/浏览器 participant DNS as DNS服务器 participant OS as 操作系统<br>内核/网卡 participant UT as Undertow<br>I/O线程 participant WT as Undertow<br>工作线程 participant SCI as ServletContext-<br>Initializer participant DS as Dispatcher-<br>Servlet participant SC as Spring容器<br>(ApplicationContext) participant MVC as Spring MVC<br>组件 participant DB as 数据库 Note over U, DB: 阶段1: 应用启动阶段 rect rgb(240, 255, 240) Note over SC, SCI: 1. Spring容器启动 SC->>SC: SpringApplication.run()<br>创建ApplicationContext SC->>SC: 扫描@Component、@Bean等<br>初始化所有单例Bean SC->>DS: 创建DispatcherServlet Bean<br>@Bean DispatcherServlet Note over SC, SCI: 2. 自动配置机制 SC->>SCI: 创建ServletRegistrationBean<br>(实现ServletContextInitializer) SCI->>SCI: 包含DispatcherServlet和URL映射配置 Note over UT, SCI: 3. Undertow服务器启动 SC->>UT: 创建Undertow实例<br>配置I/O线程(16)和工作线程(512) UT->>UT: 绑定端口8080<br>启动事件监听循环 Note over UT, SCI: 4. Servlet注册回调 UT->>SCI: 回调onStartup()方法<br>(通过TomcatStarter桥接) SCI->>UT: 调用servletContext.addServlet()<br>注册DispatcherServlet到Undertow UT->>UT: 完成Servlet注册<br>更新URL映射表 end Note over U, DB: 阶段2: DNS解析和网络传输 rect rgb(240, 248, 255) U->>DNS: DNS查询<br>example.com → 192.168.1.100 DNS->>U: 返回IP地址 U->>OS: HTTP请求 GET /api/users<br>TCP三次握手建立连接 OS->>OS: 网卡接收数据→DMA→内核缓冲区 end Note over U, DB: 阶段3: Undertow接收和处理 rect rgb(255, 248, 240) OS->>UT: 通过epoll通知数据就绪<br>I/O线程从内核缓冲区读取 UT->>UT: 解析HTTP协议<br>创建HttpServerExchange UT->>WT: 从线程池(512)借用工作线程<br>传递请求信息 Note over WT, DS: 4. Servlet处理链 WT->>DS: 调用service()方法<br>请求进入Spring MVC世界 DS->>MVC: doDispatch()开始处理<br>查找HandlerMapping MVC->>MVC: 执行Interceptor.preHandle()<br>参数绑定验证 MVC->>SC: 调用@Controller方法<br>执行业务逻辑 SC->>DB: 执行SQL查询<br>工作线程等待数据库响应 DB->>SC: 返回查询结果 SC->>MVC: 返回ModelAndView<br>执行Interceptor.postHandle() MVC->>DS: 处理完成<br>准备响应数据 DS->>WT: 返回响应给工作线程 WT->>UT: 工作线程释放<br>响应数据交还I/O线程 end Note over U, DB: 阶段4: 响应返回 rect rgb(248, 240, 255) UT->>OS: I/O线程写入内核发送缓冲区 OS->>U: 操作系统组包发送HTTP响应 U->>U: 浏览器接收响应<br>解析HTML/JSON渲染页面 UT->>UT: 保持HTTP连接<br>等待下一个请求 end Note over U, DB: 阶段5: 连接管理(后续请求) U->>UT: 同一连接的后续请求<br>复用现有TCP连接 UT->>WT: 直接分配工作线程处理<br>跳过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解析过程

  1. 浏览器缓存检查 → 2. 系统缓存检查 → 3. 路由器缓存检查 → 4. ISP DNS缓存 → 5. 递归查询 → 6. 返回IP地址

TCP连接复用

  1. 建立连接后,后续请求复用同一连接
  2. 第一次请求: TCP握手 → HTTP请求/响应
  3. 第二次请求: HTTP请求/响应(复用连接)
  4. 第三次请求: HTTP请求/响应(复用连接)

4. 线程模型的关键点

Undertow的两级线程池

  • I/O线程(16个) :非阻塞处理网络I/O,不执行业务逻辑
  • 工作线程(512个) :阻塞式处理业务逻辑,可被挂起等待IO

优势: 工作线程在等待数据库时可以处理其他请求

  • 工作线程1: 开始处理请求A → 等待数据库 → 挂起
  • 工作线程1: 被唤醒处理请求B → 快速计算 → 返回响应
  • 工作线程1: 数据库响应到达 → 继续处理请求A → 返回响应

完整数据流总结

  1. 启动阶段:Spring容器 → 创建Bean → 启动Undertow → 注册Servlet
  2. 请求接收:DNS解析 → 建立TCP连接 → 内核接收 → Undertow I/O线程
  3. 业务处理:工作线程 → DispatcherServlet → Spring MVC → 业务逻辑 → 数据库
  4. 响应返回:处理结果 → 工作线程 → I/O线程 → 内核发送 → 网络传输 → 浏览器
相关推荐
掘金一周11 分钟前
想问问掘友们:AI 时代,资深开发的核心价值到底在哪里?| 沸点周刊 7.23
前端·人工智能·后端
geovindu1 小时前
java: Facade Pattern
java·开发语言·后端·外观模式·结构型模式
布朗克1681 小时前
Go 入门到精通-29-测试与基准
开发语言·后端·golang·测试与基准
你驴我1 小时前
WhatsApp Cloud API 速率限制下的令牌桶与退避策略实践
网络·后端·python
ClouGence2 小时前
SAP HANA 到 Doris 数据迁移:4 种方案对比与迁移教程
数据库·后端·dba
LVZ2 小时前
用了半年 AI 写代码,最烦的不是代码,是环境
前端·后端·开源
云边有个稻草人2 小时前
从一条危险的 WHERE 条件说起:金仓数据库逻辑安全警示
后端
用户7713970207062 小时前
从一脸懵到熟练使用:我的C#CAD二次开发日常中那些“反人类“的循环技巧
后端
JaneConan3 小时前
鸿蒙报错速查:arkts-no-any any 类型禁用,用了就炸,根因 + 真解法
后端·harmonyos
颜酱3 小时前
# 02 | 搭骨架:用 LangGraph 编排 12 步工作流(思路)
前端·人工智能·后端