Tuesday 27 November 2012

Comparing Servlet 3.0 Asynchronous Servlets with Jetty Continuations

Why do we need Asynchronous Servlets?
Asynchronous Servlets are useful when a Servlet needs to wait for resources or events. For example, a Servlet may need to wait for:
  • Response from Remote Web Resource
  • A JDBC connection
  • A JMS message
  • An application event
Because, waiting is an inefficient operation which consumes resources such threads, database connections, buffers etc.

Containers implementing Asynchronous Servlets:
  • Jetty 6 supporting Continuations
  • Containers implementing Servlet 3.0
  • Jetty 7( onwards supports both Jetty Continuations and Servlet 3.0 Asynchronous Servlets

How does Asynchronous Servlets Work:

  • Servlet/Filter can begin asynchronous processing
  • Thread will return to the container after the asynchronous processing of the request has started. The Servlet response will not be committed like default Servlet Life cycle.
  • Another thread may either 
    • generate the response and call complete 
    • or dispatch the request to run in container context.

Servlet 3.0 introducing new features compared to Jetty 6  


The Servlet 3.0 asynchronous API introduced some new asynchronous features not supported by jetty 6 continuations:
  • Ability to complete an asynchronous request without re-dispatching
  • Listeners for asynchronous events
  • Dispatching asynchronous requests to specific contexts and/or resource
  • Support for wrapping requests and responses.
  • Applying Filters during dispatch mode.
Later, Jetty started adopting above features  except "Applying Filters during dispatch mode" since Jetty 7.

Comparing API: Jetty Continuation Vs Servlet 3.0 Async Servlet

FeatureJetty ContinuationServlet 3.0
SuspendContinuation.suspend(HttpServletResponse)HttpServletRequest.startAsync()
ResumeContinuation.resume()AsyncContext.dispatch()
CompleteContinuation.complete()AsyncContext.complete()

Understanding Asynchronous Servlets(Code):

Lets take an example where a Servlet blocks while waiting for Remote Web Service call to return and try to understand how the Servlets were written without the invent of Asynchronous Servlets , Jetty 6 Continuations and Servlet 3.0 Asynchronous Servlets.

Synchronous Servlets

public class RemoteWebServiceServlet extends HttpServlet {
      public void doGet(HttpServletRequest req, HttpServletResponse res) {
             Object result  = makeRemoteWebService(...);
                       writeResponse(result);
    }
}

 Asynchronous Servlet using Servlet 3.0

@WebServlet(async=“true”)
public class AsyncServlet extends HttpServlet {
     public void doGet(HttpServletRequest req, HttpServletResponse res) {
          // Check if request it is not async dispatch
          if (!req.isAsyncStarted()) {
               AsyncContext ctx = req.startAsync(req, res); //Start Async Processing
               ctx.start(new  RemoteServiceHandler() implements Runnable {
                    public void run() {
                        Object result  = makeRemoteWebService(...);
                         request.setAttribute("result", result);   
                         ctx.dispatch(); // Re-dispatch/ resume to generate response
                    }
               });
          } else {
               Object result = request.getAttribute("result");
               writeResponse(result);
          }
     }
}

  Asynchronous Servlet using Jetty Continuations:

 public class AsyncServlet extends HttpServlet {
     public void doGet(HttpServletRequest req, HttpServletResponse res) {
          /
// Check if request it is not async dispatch
          Object result = request.getAttribute("result");
          if (result == null) {
               Continuation continuation = ContinuationSupport.getContinuation(request);
       continuation.suspend(response);
//Start Async Processing
              threadpool.submit(new  RemoteServiceHandler() implements Runnable {
                    public void run() {
                        Object result  = makeRemoteWebService(...);
                         request.setAttribute("result", result);  
                        continuation.resume();
// Re-dispatch/ resume to generate response
                    }
               });
          } else {
               Object result = request.getAttribute("result");
               writeResponse(result);
          }
     }
}

 Internals of Servlet 3.0 Async and Jetty 6 Continuations:

Now, we will try to understand how Servlet 3.0 Async and Jetty 6 Continuations work internally. Infact, both work in the same way.   If you see below, there is a single implementation class for both Servlet 3.0 Async and Jetty 6 Contination:

public class AsyncContinuation implements AsyncContext, Continuation { 
               ...........
}
 And the below code shows that Jetty HttpServletRequest implementation internally uses Continuation API:

public class Request implements HttpServletRequest {
..............
public AsyncContext startAsync() throws IllegalStateException
    {
        if (!_asyncSupported)
            throw new IllegalStateException("!asyncSupported");
        _async.suspend();
        return _async;
    }
}
  

No comments:

Post a Comment