Skip to main content

startAsync in Servlet 3.0

Posted by swchan2 on September 8, 2011 at 5:15 PM PDT

Prior to Servlet 3.0, a servlet may need to wait for a long operation to complete and can cause thread starvation in web container. In Servlet 3.0, asynchronous processing is introduced to handle this situation.

There is a lot of information about asynchronous processing in Servlet 3.0. In this blog, we will take a look at two aspects of startAsync.

When will javax.servlet.AsyncListener#onStartAsync(AsyncEvent event) method be invoked?

Let us take a look at a simple example.

    AsyncContext asyncContext = httpServletRequest.startAsync();
    AsyncListener myAsyncListener = new AsyncListener() { .... };
    asyncContext.addListener(myAsyncListener);

Notice that myAsyncListener.onStartAsync(AsyncEvent) method is not invoked in above example because asynchronous processing has already been started. When will it be called? According to Servlet 3.0 spec, AsyncListener#onStartAsync(AsyncEvent) will be invoked when the AsyncContext is reinitialized, for instance, when AsyncContext#dispatch() is invoked. As a remark, all the asyncListeners added will be removed during reinitialization and one has to add async listeners if necessary.

In a servlet with given request and response, are the AsyncContext request.startAsync() and request.startAsync(request, response) the same?

The above two AsyncContext are almost, but not the same. The difference is in the behavior of AsynContext#dispatch(). From javadoc of AsynContext#dispatch(),

If the asynchronous cycle was started with ServletRequest#startAsync(ServletRequest, ServletResponse), and the request passed is an instance of HttpServletRequest, then the dispatch is to the URI returned by HttpServletRequest.getRequestURI().
Otherwise, the dispatch is to the URI of the request when it was last dispatched by the container.

The following example illustrate what it means. Suppose we have three HTTP servlets: A, B, C with resource paths /a, /b, /c (relative to context root) respectively.
In Servlet A, we have
            request.getRequestDispatcher("/b").forward(request, response);   

In Servlet B, we have
            request.getRequestDispatcher("/c").forward(request, response);   

In Servlet C, we have following two cases:

  1. request.startAsync().dispatch(); // to /b
    It will dispatch to the last dispatched URI, which corresponds to /b.
  2. request.startAsync(request, response).dispatch(); // to /c
    It will dispatch to request.getRequestURI(), which corresponds to /c.