一、同步和的异步 Servlet
Servlet 3.0 的异步处理支持特性,使Servlet 线程不再需要一直阻塞。
1.同步的 Servlet
public class SyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().write("data:Data chunk\n");
response.getWriter().flush();
}
}
2.异步的 Servlet
使用 request.startAsync() 开启异步
使用 asyncContext.complete() 结束
public class AsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0);
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(5);
ServletResponse response1 = asyncContext.getResponse();
response1.getWriter().write("data:Data chunk\n");
response1.getWriter().flush();
asyncContext.complete();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}).start();
}
}
二、原理
1) response.getWriter().flush() 会调用 coyoteResponse.action(ActionCode.CLIENT_FLUSH, null) 把数据发送给客户端
2) response.finishResponse() 会调用 coyoteResponse.action(ActionCode.CLOSE, null) 通知客户端结束
3) asyncContext.complete() 会调用 request.getCoyoteRequest().action(ActionCode.ASYNC_COMPLETE, null) 通知客户端结束
// CoyoteAdapter.java
@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception {
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
...
boolean async = false;
boolean postParseSuccess = false;
req.setRequestThread();
try {
// Parse and set Catalina and configuration specific
// request parameters
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
// check valves if we support async
request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
// Calling the container
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
}
if (request.isAsync()) {
async = true;
...
} else {
request.finishRequest();
response.finishResponse();
}
} catch (IOException e) {
// Ignore
}
...
}
// OutputBuffer.java
protected void doFlush(boolean realFlush) throws IOException {
...
coyoteResponse.action(ActionCode.CLIENT_FLUSH, null);
...
}
public void close() throws IOException {
...
coyoteResponse.action(ActionCode.CLOSE, null);
}