Background
How to Enable Asynchronous?
By default it’s turned off. It can be enabled either using annotations or in web.xml
Conclusion
Servlet 3.0 added the provision for asynchronous calls, which provides great flexibility and avoids the need for proprietary implementation to achieve the same in web applications.
With the advent of Rich Internet
Application (RIA) and data-hungry HTML5, asynchronous calls are becoming more
and more inevitable at every level of web application, including servlet layer.
In typical “thread-per-request” model, web container assigns one thread, from
pool, for each http request and runs the doXXX method of the servlet. But in
cases where the doXXX methods need long time to complete, the thread is engaged
with the underlying request. This creates bottleneck and limits the number of
requests which can be served by web container. Although there were proprietary
implementation to achieve asynchronization (Comet apps as an example), none of
them provide true sense of it. I’ve seen many implementations where developers
trigger a new thread inside doXXX to accomplish the time-taking tasks, but the
biggest fault of such implementations is that the response is committed back to
client as soon as the doXXX method ends and then you need to poll the server to
get the result of the original request.
One of the important features of
Servlet 3.0 is the provision for Asynchronous calls. The center of this is the
AsyncContext class, which encapsulates the request and response objects and
provides methods to commit/dispatch the response at later point of time. The
noticeable difference here is that, on the completion of doXXX method, the
thread is simply returned to pool but the response is not committed. The request
and response can be retrieved from AsyncContext object later on and then
response be committed from there or dispatched to another resource (servlet or
jsp). Let’s consider an exemplary code snippet to understand it better:
@WebServlet(value = "/sample", asyncSupported = true)
public class SampleAsyncServlet extends HttpServlet {
@Override
protected
void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
AsyncContext asyncContext = req.startAsync(req, res);
asyncContext.getResponse().getWriter().println("Starting new asynchronous request…");
asyncContext.start(new LongRunner(asyncContext));
}//This
doesn’t commit response.
private
class LongRunner implements Runnable {
AsyncContext asyncContext;
public
LongRunner(AsyncContext asyncContext) {
this.asyncContext = asyncContext;
}
@Override
public
void run() {
//Do some long process here……
try {
asyncContext.getResponse().getWriter().printf("Output of long
process……”);
} catch (IOException e) {
//Handle exception
} finally {
asyncContext.complete(); //This commits the response back to client
}
}
}
}
In the above code, inside doGet
method, a new AsyncContext object is created and a new thread is started using
its start method. This start the execution in a new thread while the original
thread associated with doGet method is returned back to the pool. The response
is not yes committed to client. In the new thread, once the task is done, the
response is sent back to client using complete method of AsyncContext.
So, theoretically, the steps are
as follows:
1. Client
sends the request to web container
2. Web
container gets a thread from the pool and runs the doXXX method of the servlet
3. With
request.startAsync() method, a new AsynContext object is created which
encapsulates the req/resp.
4. You
can either start a new thread and pass it to start() method of AsyncContext
object to start long & time consuming process or store AsyncContext object
at appropriate level and retrieve later at valid trigger.
5. The
completion of method doXXX, simply releases the thread back to pool, but
response is not sent back to client.
6. Req/Resp
objects are retrieved from AsyncContext object and worked on.
Finally response is committed by calling
complete() or dispatch() method to dispatch to other resource (servlet/jsp).How to Enable Asynchronous?
By default it’s turned off. It can be enabled either using annotations or in web.xml
@WebServlet (urlPatterns = {"/sample"}, asyncSupported=true)
public class SampleServlet
extends HttpServlet {
OR
<servlet>
<servlet-name>sample</servlet-name>
<servlet-class>com.sample.servlet.SampleServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
Further ReadingConclusion
Servlet 3.0 added the provision for asynchronous calls, which provides great flexibility and avoids the need for proprietary implementation to achieve the same in web applications.