Spring:spring-web中DeferredResult的实现原理

        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个作用:

  1. 通知servlet容器,结果已存入request中,可以去获取结果了
  2. 通知servlet容器,再次调用当前url就可以获取到结果

 于是,servlet容器会再次调用此url的servlet的doPost方法获取结果。

你可能感兴趣的:(Java,spring,servlet)