客户端请求到达 Spring MVC 控制器的完整流程是一个涉及多层网络协议和框架组件的协作过程。以下是详细步骤分解:
请求传输全流程(共 8 步)
详细步骤解析
步骤 1:客户端发起请求
用户操作:在浏览器输入 URL 或点击链接(如 http://example.com/users
)
协议封装:
GET /users HTTP/1.1
Host: example.com
Accept: application/json
底层传输:浏览器通过操作系统 Socket API 发送 TCP 数据包
步骤 2:网络传输层处理
DNS 解析:
浏览器查询 example.com
→ DNS 服务器返回 IP 地址(如 192.168.1.100
)
TCP 连接:
客户端与服务器建立 TCP 三次握手
客户端 -> SYN -> 服务器
客户端 <- SYN-ACK <- 服务器
客户端 -> ACK -> 服务器
HTTP 封装:请求被封装为 TCP 数据包传输
步骤 3:服务器网络栈处理
网卡接收:服务器物理网卡接收数据帧
内核处理:
网络驱动解析以太网帧
IP 层解包获取目标 IP
TCP 层重组数据包
Socket 分发:
内核根据目标端口(如 8080)将数据交给监听该端口的进程(Tomcat/Jetty)
步骤 4:Servlet 容器处理
连接器接收(如 Tomcat Coyote):
// Tomcat NIO 伪代码
while (true) {
Socket socket = serverSocket.accept(); // 接受连接
Executor.execute(new HttpProcessor(socket)); // 交给线程池
}
HTTP 解析:
解析请求行(GET /users HTTP/1.1
)
解析头部(Host, Accept 等)
构造 HttpServletRequest
对象
步骤 5:Spring MVC 前端控制器介入
DispatcherServlet 接管:
容器调用 service()
方法
// DispatcherServlet 核心流程
protected void service(HttpServletRequest req, HttpServletResponse resp) {
doDispatch(req, resp); // 开始分发
}
请求分发:
查找 HandlerMapping → 确定目标控制器
执行拦截器链(preHandle()
)
步骤 6:路由到控制器
HandlerMapping 工作:
// 简化版映射过程
HandlerExecutionChain chain = handlerMapping.getHandler(request);
if (chain != null) {
// 找到匹配 @GetMapping("/users") 的控制器方法
controllerMethod = chain.getHandler();
}
参数绑定:
解析 @RequestParam
, @PathVariable
等注解
反序列化 @RequestBody
内容
步骤 7:控制器执行
方法调用:
// 反射调用控制器方法
Object returnValue = method.invoke(
controllerBean, // 单例控制器实例
args // 绑定后的参数数组
);
业务处理:执行开发者的业务逻辑代码
步骤 8:响应返回
结果处理:
@ResponseBody
→ 使用 HttpMessageConverter
序列化为 JSON
返回视图名称 → ViewResolver
解析为 HTML
响应写出:
// 伪代码
response.getWriter().write(json);
response.flushBuffer();
连接关闭:TCP 四次挥手释放连接
关键组件协作图
网络协议栈各层职责
层级 | 协议/组件 | 关键职责 | 示例数据单元 |
---|---|---|---|
应用层 | HTTP | 定义请求/响应格式 | GET /users HTTP/1.1 |
传输层 | TCP | 可靠传输、流量控制 | TCP Segment |
网络层 | IP | 路由寻址 | IP Packet |
数据链路层 | Ethernet/WiFi | 物理寻址(MAC) | Ethernet Frame |
物理层 | – | 比特流传输 | 比特(bit) |
Spring MVC 核心处理流程代码级解析
// DispatcherServlet 的核心分发方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// 1. 确定处理器
HandlerExecutionChain mappedHandler = getHandler(request);
// 2. 确定适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 执行拦截器预处理
if (!mappedHandler.applyPreHandle(request, response)) return;
// 4. 实际调用控制器方法
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
// 5. 渲染视图/处理响应
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(request, response, mv);
// 6. 完成处理(包括异常处理)
processDispatchResult(request, response, mappedHandler, mv, null);
}
性能优化关键点
TCP 层面:
开启 TCP_NODELAY 减少延迟
调整 keepalive 时间
# Tomcat配置
server.tomcat.connection-timeout=20000
Servlet 容器:
使用 NIO 模式
优化线程池大小
// Spring Boot配置
server.tomcat.max-threads=250
server.tomcat.accept-count=100
Spring MVC:
启用缓存(静态资源)
优化消息转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2HttpMessageConverter());
}
}
常见问题排查
请求未到达控制器:
检查 @RequestMapping
路径是否匹配
查看 Tomcat access 日志确认请求到达
400 Bad Request:
参数绑定失败(类型不匹配)
@RequestBody
JSON 解析错误
404 Not Found:
控制器未扫描到(缺少 @ComponentScan
)
URL 路径拼写错误
线程阻塞:
使用 jstack
查看线程栈
检查是否有同步锁竞争
整个流程在优化良好的系统中可在 10-100ms 内完成,其中网络传输通常占 70% 以上时间。
暂无评论内容