Spring 3.2 Rundown, Async Support

One of the features in the latest minor release of the Spring framework (3.2), is support for Servlet 3.0 “async” processing.

In this blog I’ll show you how Spring let’s you do wizardry things like long polling in a straightforward way!

In a normal web application, the client (browser) sends HTTP requests to the server, which processes information and delivers an HTTP response. While waiting for the response, the browser normally pauses and indicates that it is waiting for a response. To alleviate the client becoming “unresponsive”, this is nowadays overcome mostly by sending the request as an AJAX request. This solves the client’s problems to a great degree.

However, a situation where the processing on the server side takes an extended amount of time, may cause problems for the server. Each (AJAX) request
that clients make will “hang” on the application server and lock up resources (such threads), while the server is trying to process it. Thus, this is where the
async functionality in Servlet 3, and Spring 3.2 comes to the rescue.

Spring async support basically comes in two variations. Both methods work in a similar fashion, namely that when a request is received, the executing thread is immediately released. Processing is done in a separate thread, before the HTTP response is written back to the client. Thus from a client side, it’s not possible to distinguish that async functionality is being used.

I built a sample application for the purpose of showing these variations, including the “normal” HTTP request/response call, and I’ll show you here how to set this up yourself.

First of all, you’ll need a project setup. Look no further than the Spring MVC Showcase project on github! In my own demo project I used a similar, but simpler, setup that I won’t show here. What I will do is highlight a few important configurations:

  • Make sure your application server supports the Servlet 3.0 spec.
  • Set the <async-supported> flag to ‘true’ on your Spring dispatcher servlet.
  • Specify that the web application is a “3.0” web application in web.xml:
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

 

That’s about it.

My application loads a simple HTML page with three links:

home

When the first, called ‘normal’, is clicked, an MVC controller method is hit, which basically puts the thread to sleep for 9 seconds, before returning a view name.

When the second, called ‘async with callable’, is clicked, an MVC controller method is hit, which returns a java.util.Callable. The callable implementation sleeps for 9 seconds before returning a view name. In this case the response is written after the Callable returns the view.

When the third, called ‘async with deferred’, is clicked, an MVC controller method is hit, which returns a Spring DeferredResult typed to ModelAndView. The result is also stored in a local Collection. A separate method, scheduled by Spring to run every five seconds, is run concurrently. The thread simulates an external process or thread, by sleeping for 9 seconds before calling “setResult” on the DeferredResult stored in the collection. In this case, setting the result causes the response to be written!

To understand the differences between these methods, I took screenshots of the running Tomcat threads after having clicked each of the above links:

normal

In the normal case, you can see that the Tomcat exec thread is sleeping during execution of the controller method.

async
In the async case, you can see that the Tomcat exec thread releases execution of the controller method, and a separate thread (known by Spring) performs the “processing” before returning the response.

deferred
The deferred case is almost the same as the async one. The only difference is where the processing occurs, which in this case is the Spring initiated ‘pool-1-thread-1′ executor thread. Note that this thread could have been started from anywhere, it wouldn’t have to be known to Spring.

So in conclusion, I think it’s fair to say that Spring makes this  new functionality very easy to implement. Now you can start doing ‘long polling’ and stop hogging too much resources!

If you want to try these things out, I suggest that you take a look at the three Spring blogs on the topic and use the MVC Showcase project as your starting point.

For reference, below is the controller code used to demonstrate the above:

/**
 * @author Christian Fogel
 */
@Controller
public class AsyncDemoController {

    private final Queue<DeferredResult<ModelAndView>> eventQueue = new ConcurrentLinkedQueue<>();

    @RequestMapping("/normal")
    public String normalCall() throws InterruptedException {
        Thread.sleep(9000);
        return "normal";
    }

    @RequestMapping("/async")
    public Callable<String> asyncCall(final Model model) {
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(9000);
                return "async";
            }
        };
    }

    @RequestMapping("/deferred")
    public
    @ResponseBody
    DeferredResult<ModelAndView> deferredCall() {
        DeferredResult<ModelAndView> result = new DeferredResult<>();
        this.eventQueue.add(result);
        return result;
    }

    @Scheduled(fixedRate = 5000)
    public void simulateExternalThread() throws InterruptedException {
        Thread.sleep(9000);
        for (DeferredResult<ModelAndView> result : this.eventQueue) {
            result.setResult(new ModelAndView("deferred"));
            this.eventQueue.remove(result);
        }
    }

}

 

 

6 thoughts on “Spring 3.2 Rundown, Async Support

  1. Pingback: Spring 3.2 Rundown, Intro | Not Purely Technical

  2. Hi christian, i have two question.
    1. In simulateExternalThread(), it looks run single thread and how to separate job every request from servlet(controller).
    2. It seems that use servlet async can let the servlet not so busy, but in tomcat if the maxThread is 200, the async servlet still can’t service more than 200 request in the same time, the exceeding request is still need to wait.
    could you clear it up for me.

    thanks

    • 1. Not sure I understand you correctly, but that thread is annotated with @Scheduled, which means it will be executed by Spring, in another thread, at regular intervals. The method is just simulating some external thread where a long-running task is being processed!
      2. The request thread is freed, made available, during the processing of the controller methods so it will indeed free up your tomcat request thread pool. This is a feature of Servlet 3.
      Hope this helps!

      • 1.If there are two request A and B, A request need to cost 10 sec to handle on query and B need to cost 3 sec to handle on query, but they all handle in the same thread on simulateExternalThread method. They are not work on different thread, so B request still need to wait A long-running task work complete?!
        2.I use jmeter and set user thread number to request “asyncCall”, 20x thread is the number async-servlet can serve. it seems no big different with normal servlet, so it make me confuse…
        (here’s my test project https://github.com/topvas7450/servlet3async)

Leave a Reply to Christian Fogel Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>