核心机制:Servlet 异步处理(AsyncContext)
Servlet 3.0 引入 javax.servlet.AsyncContext
,允许将请求“挂起”,释放容器线程,由后台线程完成处理。
启用异步支持
@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {// ...
}
⚠️ 必须设置
asyncSupported = true
,否则调用startAsync()
会抛异常。
🔄 异步请求生命周期
+------------------+| 客户端发起请求 |+--------+---------+|v+------------------+ +------------------+| Tomcat 分配线程 | ----> | 调用 startAsync() || (短暂占用) | +--------+---------++------------------+ |v+----------------------+| 释放 Tomcat 线程 || 可处理其他请求 |+----------+-----------+|v+----------------------+| 后台线程执行耗时任务 || (如远程调用、计算) |+----------+-----------+|v+----------------------+| 任务完成,调用 || asyncContext.complete()|+----------+-----------+|v+----------------------+| 写响应给客户端 |+----------------------+
📌 关键优势:
- Tomcat 线程快速释放,提高吞吐量
- 用少量线程支撑高并发
- 实现长连接、SSE、WebSocket 等场景
实战:开发异步 Servlet
场景:模拟调用慢速外部 API
@WebServlet(urlPatterns = "/slow-api", asyncSupported = true)
public class SlowApiServlet extends HttpServlet {private final ExecutorService executor = Executors.newFixedThreadPool(10); // 后台线程池@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 1. 启动异步上下文AsyncContext asyncContext = req.startAsync();asyncContext.setTimeout(30_000); // 设置超时时间// 2. 提交任务到后台线程池executor.submit(() -> {try {// 模拟耗时操作(如远程调用)Thread.sleep(5000);// 3. 设置响应内容resp.setContentType("application/json");resp.getWriter().write("{\"result\": \"success\", \"data\": \"来自慢接口的数据\"}");// 4. 完成异步请求asyncContext.complete();} catch (Exception e) {e.printStackTrace();try {resp.setStatus(500);resp.getWriter().write("{\"error\": \"服务器内部错误\"}");asyncContext.complete();} catch (IOException ioException) {ioException.printStackTrace();}}});}
}
🧪 高级用法:异步超时与错误处理
// 设置超时回调
asyncContext.addListener(new AsyncListener() {@Overridepublic void onTimeout(AsyncEvent event) throws IOException {HttpServletResponse resp = (HttpServletResponse) event.getSuppliedResponse();resp.getWriter().write("{\"error\": \"请求超时\"}");event.getAsyncContext().complete();}@Overridepublic void onError(AsyncEvent event) throws IOException {event.getAsyncContext().complete();}@Overridepublic void onComplete(AsyncEvent event) throws IOException {System.out.println("异步请求已完成");}@Overridepublic void onStartAsync(AsyncEvent event) throws IOException {}
});