下面给你的是容器实现者级别的 Servlet Container 运行模型。
不讲 Tomcat 参数、不讲 web.xml,只讲它内部是如何驱动一次 HTTP 请求的。
一句话总览
Servlet Container 是一个“HTTP → 线程 → Filter → Servlet → Response”的调度内核。
Spring、Spring MVC、Spring Security,全都只是挂在它后面的插件。
一、整体执行路径
一次 HTTP 请求在容器中的真实路径是:
TCP 连接
↓
HTTP 解析(Connector)
↓
Socket → Request / Response 对象
↓
分配工作线程(Executor)
↓
Engine
↓
Host(虚拟主机)
↓
Context(WebApp)
↓
Wrapper(Servlet)
↓
FilterChain
↓
Servlet.service()
↓
Controller
Spring 只在 Servlet 之后。
二、线程模型(你性能的根源)
以 Tomcat 为例:
Acceptor 线程 → 接 TCP
Poller 线程 → 监听 Socket 可读
Worker 线程 → 处理请求
当 Socket 可读:
Poller → 把 Socket 丢给 Executor → 一个 Worker 线程
这个 Worker 线程贯穿整个请求生命周期。
这就是为什么:
- Servlet 是阻塞模型
- Spring MVC 是线程绑定模型
- Spring Security 用 ThreadLocal
三、Request 是如何被路由的
当线程接管请求后:
Engine
→ 找域名
Host
→ 找 Context path
Context
→ 找 URL pattern
Wrapper
→ 找 Servlet
这是:
example.com/app/api/user
└─ Context
└─ /api/*
└─ DispatcherServlet
四、FilterChain:一切中间件的根
在 Servlet 之前:
Request
→ Filter1
→ Filter2
→ Filter3
→ Servlet
←
←
←
Filter 可以:
- 修改 Request
- 拦截
- 重定向
- 包装 Response
Spring Security 就是一个超级 Filter。
五、DispatcherServlet 在容器中的真实地位
从容器视角:
Tomcat
→ DispatcherServlet(普通 Servlet)
→ HandlerMapping
→ HandlerAdapter
→ Controller
Tomcat 完全不知道:
- @Controller
- @RestController
- @RequestMapping
它只知道:
“我在调用一个 Servlet 的 service()”
六、为什么 Session、Security、事务都能工作
因为:
一个请求 = 一个线程
一个线程 = 一个 ThreadLocal 容器
Spring 用这个模型存:
- SecurityContext
- Transaction
- RequestContext
这是 Servlet 规范最重要的隐含契约。
七、为什么 WebFlux 不用 Servlet
Servlet 模型:
一个请求霸占一个线程
WebFlux(Netty):
一个线程处理成千上万连接
但 Spring MVC、Spring Security 的经典模型是建立在 Servlet 线程模型之上的。
八、终极工程结论
Servlet Container 是 Java Web 世界真正的操作系统内核。
Spring 只是跑在它之上的应用框架。
你只要记住一条主线就够了:
Socket → Thread → FilterChain → Servlet → Spring → Controller
如果你愿意,我可以下一步给你画:
- Spring Security 在 FilterChain 中的准确位置
- 或 Tomcat vs Netty 的执行路径对比
- 或 为什么虚拟线程正在改变 Servlet 容器的未来
filter中可以做哪些操作
这是一个非常关键的问题。
Filter 能做什么,决定了 Spring Security、日志、网关、限流、审计、甚至 WAF 能做什么。
我给你一份容器级能力清单。
一句话总览
Filter 是 Servlet 容器赋予你的“内核态钩子”。
它可以在 Controller 之前和之后:
- 查看
- 修改
- 替换
- 阻断
整个 HTTP 请求与响应。
一、Filter 能接触到什么
在 doFilter(request, response, chain) 中你能拿到:
请求侧
- URL / QueryString
- Headers
- Cookies
- Body(InputStream)
- Remote IP
- TLS 信息
- Session
响应侧
- Status code
- Headers
- Cookies
- Body(OutputStream)
- Redirect
- Commit 状态
二、Filter 能做的核心操作
1️⃣ 直接放行(什么都不做)
chain.doFilter(req, resp);
这是 99% 请求的路径。
2️⃣ 阻断请求(安全与风控)
resp.sendError(401);
return;
常见用途:
- 认证失败
- 黑名单 IP
- CSRF
- WAF
Spring Security 就是干这个。
3️⃣ 修改 Request(伪造客户端)
HttpServletRequestWrapper
可以:
- 添加 Header
- 改参数
- 替换 Body
例如:
- JWT → 注入 userId
- Gateway → 注入租户 ID
- 反向代理
4️⃣ 修改 Response(统一出口)
你可以:
- 包一层 HttpServletResponseWrapper
- 改返回 JSON
- 注入 header
- 压缩 / 加密
例如:
- 全站加 X-Trace-Id
- 错误统一格式
5️⃣ 接管整个请求(短路)
你可以:
resp.getWriter().write("blocked");
return;
Controller 完全不会执行。
网关、Mock Server、熔断器都这么干。
6️⃣ 捕获异常(全局兜底)
try {
chain.doFilter(...)
} catch (Exception e) {
log(e);
writeError(resp);
}
比 Spring @ControllerAdvice 还早。
7️⃣ 记录与审计
你可以:
- 读 body
- 记 header
- 记用户
- 记响应
这是:
- 日志
- 审计
- 风控
- APM 的基础
三、Filter 为什么这么强
因为它运行在:
Socket 已建立
Controller 尚未执行
这是 Web 世界唯一的“特权位置”。
你可以:
- 改事实(Request)
- 改结果(Response)
- 改命运(放行 or 拒绝)
四、Spring Security 为什么一定用 Filter
因为只有 Filter:
- 能挡住 Controller
- 能接管 Session
- 能统一入口
- 能跨所有 URL
如果放在 Controller:
攻击请求已经进来了。
五、Filter 的真正边界
Filter 不能:
- 控制 TCP
- 控制 TLS
- 控制 HTTP 解析
- 控制路由到哪个虚拟主机
那是 Connector 层的事。
六、终极结论
Filter 是 Java Web 的“内核模块”。
理解 Filter,你就理解了:
- Spring Security
- API Gateway
- 网关
- 登录系统
- 限流
- WAF
- 统一认证
如果你愿意,我可以下一步给你:
- Spring Security 中 15 个 Filter 的真实执行顺序
- 或 你自己写一个 JWT Filter 的标准架构
- 或 Filter vs Interceptor vs AOP 的真实边界
filter里阻断请求是指什么? 可以修改了response后就直接return吗
这是一个关键且容易被误解的点,你问得非常准确。
一句话结论
是的,在 Filter 里你可以在写完 Response 后直接 return,这就叫“阻断请求”。
它的效果是:
这个 HTTP 请求被你“终结”在 Filter 层,后面的 Filter、Servlet、Controller 全部不会执行。
一次请求的两条命运
在 Filter 中,一个请求只有两种走法:
A) chain.doFilter(req, resp) → 继续向下走
B) 不调用 chain.doFilter → 请求在这里终止
你只要不调用 chain.doFilter,你就已经“拦截”了它。
二、阻断请求的真实含义
比如你在 Spring Security 里:
if (!authenticated) {
resp.setStatus(401);
resp.getWriter().write("Unauthorized");
return;
}
chain.doFilter(req, resp);
发生了什么:
Client → Filter
↳ 写 401
↳ return
Tomcat 认为:Response 已经完成
Controller 永远不会执行
这就是:
- 未登录
- 没权限
- CSRF 失败
- 黑名单 IP
- Token 失效
的底层机制。
三、你可以在 Filter 里做哪些“终结型操作”
你可以:
| 操作 | 作用 |
| resp.sendError(403) | 直接拒绝 |
| resp.sendRedirect() | 重定向 |
| resp.getWriter().write() | 直接返回 JSON |
| resp.setStatus(401) | 设置 HTTP 结果 |
| resp.setHeader() | 设置响应头 |
然后:
return;
请求生命周期就结束了。
四、Servlet 容器如何理解这个 return
容器只关心一件事:
“你有没有调用 chain.doFilter()?”
没有 = 你截断了链。
之后:
- Tomcat 会把 Response flush 给客户端
- Socket 关闭或复用
- 请求结束
五、为什么这比 Controller 抛异常更强
Controller 层:
请求已经进入业务系统
Filter 层:
请求还在“门口”
所以:
- WAF
- Auth
- Gateway
- IP 限制
只能放在 Filter。
六、一个极重要的注意点
⚠️ 一旦你写了 response,就不要再调用 chain.doFilter()
否则你会得到:
- “Response already committed”
- 内容混乱
- 安全漏洞
正确模式永远是:
if (block) {
writeResponse();
return;
}
chain.doFilter(...);
七、工程结论
Filter 是 HTTP 请求的“生死裁判”。
你在这里 return,
Controller 连“知道你来过”都不会知道。
如果你愿意,我可以下一步给你:
- Spring Security 是在哪个 Filter 里做这个 return 的
- 或 JWT Filter 正确阻断的标准写法
- 或 Tomcat 在 response commit 之后发生了什么