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;
    }
}
  

Why do you need a Custom Classloader?


Java Runtime loads the classes dynamically at runtime using class loaders. By default a JVM will consists of these three class loaders:
  •  BootStrap Class loader This is the classloader which is loads all the core classes required by the JVM. They are basically the Java classes from the packages like java.lang.*, java.io.*, java.util.* etc. One can append additional class locations to this class loader using -Xbootclasspath/p: and -Xbootclasspath/a: JVM options.
  • Extension Class loader It is the classloader which is an alternative to the BootStrap class loader. One can drop the additional classes packaged in JAR file  in /lib/ext folder to get it picked by JVM.
  • System Class loader It is the classloader  which loads the classes specified in the CLASSPATH. It is also called as application classloader.
JVM allows you  to create custom class loader which can address several problems. They are mostly useful in larger architectures consisting of several module/applications. Here are the advantages of the custom class loader:
  • Modular architecture They allow you to define multiple class loader allowing modular architecture. Each module can have their own classloader.
  • Isolation Clearly defines the scope of the class to within the class loader. It avoid conflicts if a class is present in two modules.
  • Support Versioning Supports different versions of class within same VM for different modules.
  • Memory Management Classes can be loaded and unloaded whenever required.
  • Load classes from anywhere Classes can be loaded from anywhere, for ex, Database, Networks, or even define it on the fly.
  • Add resources or classes dynamically All the above features allows you add classes or resources dynamically.
  • Runtime Reloading Modified Classes Allows you to reload a class or classes at runtime by creating a child class loader to the actual class loader, which contains the modified classes.
A good example of Custom class loader is JavaEE Application Server. Where each Web or Enterprise application will be class loader by itself.