核心机制: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 {}
});