spring-web中DeferredResult是采用异步servlet实现的,以下是通过servlet的代码模拟DeferredResult的实现。
import java.io.IOException;
import java.util.concurrent.Executors;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(value = "/testComplete", asyncSupported = true)
public class IssueServlet extends HttpServlet {
private static final long serialVersionUID = -2504425408734161943L;
private static final String CTX_RESULT = "CTX_RESULT";
// true: sync; false: async
private boolean syncHandling = true;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String result = (String) request.getAttribute(CTX_RESULT);
if (result != null) {
response.getWriter().write(result);
return;
}
AsyncContext asyncContext = request.startAsync();
boolean isAsyncStarted01 = request.isAsyncStarted();
System.out.println("isAsyncStarted01:" + isAsyncStarted01);
// set return result mock DeferredResult.setResult(...);
setResult(request, asyncContext);
boolean isAsyncStarted02 = request.isAsyncStarted();
System.out.println("isAsyncStarted02:" + isAsyncStarted02);
if (isAsyncStarted02) {
return;
} else {
String ctxPath = request.getContextPath();
String url = request.getRequestURI();
System.out.println(ctxPath + "," + url);
request.getRequestDispatcher(ctxPath + url).forward(request, response);
}
}
public void setResult(HttpServletRequest request, AsyncContext asyncContext) {
// (1) set result before doPost return,
if (syncHandling) {
// make result
String ret = "this is a test";
request.setAttribute(CTX_RESULT, ret);
asyncContext.dispatch(); //
} else {
// (2) set result after doPost return,
Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
try {
Thread.sleep(5); // mock time-consuming
} catch (InterruptedException e) {
}
// make result
String ret = "this is a test";
request.setAttribute(CTX_RESULT, ret);
asyncContext.dispatch();
}
});
}
}
}
其中,setResult(...)是模拟DeferredResult.setResult(...)的操作,主要是将生成的结果存入request中。
生成的结果存入request中的操作可以是在当前线程中完成,也可以在其它线程中完成,但最重要的是要在结果存入request后调用asyncContext.dispatch()。
asyncContext.dispatch()主要有2个作用:
- 通知servlet容器,结果已存入request中,可以去获取结果了
- 通知servlet容器,再次调用当前url就可以获取到结果
于是,servlet容器会再次调用此url的servlet的doPost方法获取结果。