Skip to main content

Asynchronous support in Servlet 3.0

Posted by mode on December 10, 2008 at 5:50 PM PST

After the last couple of entries I have gotten requests for more details on how the async works. So I decided to write this up in a blog to share what the async support looks like in the Servlet 3.0 public review draft.

There are a couple of use cases that we are trying to handle with the async support in Servlet 3.0 -

  • Wait for a resource to become available (JDBC, call to webservice)
  • Generate response asynchronously
  • Use the existing frameworks to generate responses after waiting for the async operation to complete

Keeping this in mind the API that the expert group has agreed upon for async is as follows.

  • Annotation attributes in the @WebServlet and @ServletFilter annotations that indicates if a Servlet or a Filter supports async. The attribute is asyncSupported.
  • To initiate an async operation there are methods on ServletRequest - startAsync(req, res) and startAsync() (difference described below).
  • Call to startAsync returns an AsyncContext initialized with the request and response objects passed to the startAsync call.
  • AsyncContext.forward(path) and AsyncContext.forward() that forwards the request back to the container so you can use frameworks like JSP to generate the response.
  • AsyncContext.complete() indicates that the developer is done processing the request and generating the appropriate response.
  • There are a few more methods in ServletRequest like isAsyncSupported and isAsyncStarted that can be used by applications to determine if async operations are supported or started.
  • There is also a new listener - AsyncListener that applications can use to get notified of when async processing is completed or if a timeout occurs.

To initiate async processing there are two methods available - one that takes a request and response (startAsync(req, res) ) and one that does not take any parameters (startAsync()). The difference between the two method signatures is that the startAsync() with no parameters implicitly uses the original request and response while the startAsync(req, res) uses the request and response objects passed in. The request and response passed in can be wrapped by filters or other servlets earlier in the request processing chain. The AsyncContext is initialized appropriately with the request and response depending on the method used. Caution must be taken when wrapping the response and calling the no arguments startAsync(). If any data has been written to the wrapped response and not flushed to the underlying response stream you could lose the data.

Similarly after the async processing is over if you choose to forward the request back to run in the context of the web container there are three methods that are available in the AsyncContext that enable this. forward(path), forward(ServletContext, path) and forward().

  • forward() no args forwards back to the "original url" or if a forward (AsyncContext or RequestDispatcher forward) has occured after an async context has been initialized then the no args forward will forward to the path that was used by the AsyncContext / RequestDispatcher to forward to.
  • forward(path) forwards to the path relative to the context of the request
  • forward(ServletContext, path) forwards to the path relative to the context specified.

    Below is an example that shows a simple web application that is waiting for a webservice call to return and then rendering the response. Note the actual code for calling the web service itself is not included.

    @WebServlet("/foo" asyncSupported=true)
    public class MyServlet extends HttpServlet {
        public void doGet(HttpServletRequest req, HttpServletResponse res) {
            ...
            AsyncContext aCtx = request.startAsync(req, res);
            ScheduledThreadPoolExecutor executor = new ThreadPoolExecutor(10);
            executor.execute(new AsyncWebService(aCtx));
        }
    }
    public class AsyncWebService implements Runnable {
        AsyncContext ctx;
        public AsyncWebService(AsyncContext ctx) {
             this.ctx = ctx;
        }
        public void run() {
            // Invoke web service and save result in request attribute
            // Forward the request to render the result to a JSP.
            ctx.forward("/render.jsp");
        }
    }

    If you would like to try it out use the nightly build of the GlassFish trunk and post any issues that you run into at webtier@glassfish.dev.java.net which the GlassFish webtier team monitors closely.

    Related Topics >>

Comments

What happened to the AsyncContext.forward(..) methods? They ...

What happened to the AsyncContext.forward(..) methods? They don't seem to be part of the public API. http://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html

This may be just my ignorance ... but ... from the code here, it looks like the request handling is going to spawn a thread that sits around until the web service returns and then render the response ... isn't the point of having the non-blocking IO to avoid consuming threads while we wait? Or am I missing something???

I would say it's long overdue actually. A lot of web pages "kick off" processes as part web navigation or requests that don't have to tie up clients. Analytical packages and content management systems come to mind. Can't wait to see this rolled out in general.

can Asynchronous improve performance? I think there is a thread-pool for servlets on most application servers, why we need this?