@ -1567,6 +1567,18 @@ public String processSubmit(<emphasis role="bold">@ModelAttribute("pet") Pet pet
@@ -1567,6 +1567,18 @@ public String processSubmit(<emphasis role="bold">@ModelAttribute("pet") Pet pet
linkend="mvc-ann-httpentity" />.</para>
</listitem>
<listitem>
<para>A <interfacename>Callable<?></interfacename> can
be returned when the application wants to produce the return
value asynchronously in a thread managed by Spring MVC.</para>
</listitem>
<listitem>
<para>A <classname>DeferredResult<?></classname> can
be returned when the application wants to produce the return
value from a thread of its own choosing.</para>
</listitem>
<listitem>
<para>Any other return type is considered to be a single model
attribute to be exposed to the view, using the attribute name
@ -1576,6 +1588,7 @@ public String processSubmit(<emphasis role="bold">@ModelAttribute("pet") Pet pet
@@ -1576,6 +1588,7 @@ public String processSubmit(<emphasis role="bold">@ModelAttribute("pet") Pet pet
objects and the results of <literal>@ModelAttribute</literal>
annotated reference data accessor methods.</para>
</listitem>
</itemizedlist></para>
</section>
@ -2359,6 +2372,228 @@ public String myHandleMethod(WebRequest webRequest, Model model) {
@@ -2359,6 +2372,228 @@ public String myHandleMethod(WebRequest webRequest, Model model) {
</section>
</section>
<sectionxml:id="mvc-ann-async">
<title>Asynchronous Request Processing</title>
<para>Spring MVC 3.2 introduced Servlet 3 based asynchronous request
processing. Instead of returning a value, as usual, a controller method
can now return a <interfacename>java.util.concurrent.Callable</interfacename>
and produce the return value from a separate thread. Meanwhile the main Servlet
container thread is released and allowed to process other requests.
Spring MVC invokes the <interfacename>Callable</interfacename> in a
separate thread with the help of a <interfacename>TaskExecutor</interfacename>
and when the <interfacename>Callable</interfacename> returns, the
request is dispatched back to the Servlet container to resume
processing with the value returned by the
<interfacename>Callable</interfacename>.
Here is an example controller method:</para>
<programlistinglanguage="java">
@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {
return new Callable<String>() {
public Object call() throws Exception {
// ...
return "someView";
}
};
}</programlisting>
<para>A second option is for the controller to return an instance of
<classname>DeferredResult</classname>. In this case the return value
will also be produced from a separate thread. However, that thread is not
known to Spring MVC. For example the result may be produced in response
to some external event such as a JMS message, a scheduled task, etc.
Here is an example controller method:</para>
<programlistinglanguage="java">
@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
DeferredResult<String> deferredResult = new DeferredResult<String>();
// Save the deferredResult in in-memory queue ...
return deferredResult;
}
// In some other thread...
deferredResult.setResult(data);
</programlisting>
<para>This may be difficult to understand without any knowledge of the
Servlet 3 async processing feature. It would certainly help to read up on it.
At a very minimum consider the following basic facts:</para>
to the current <interfacename>DispatcherType</interfacename>, which
can be used to distinguish if a <interfacename>Servlet</interfacename> or
a <interfacename>Filter</interfacename> is processing on
the initial request processing thread and when it is processing in
an async dispatch.</para>
</listitem>
</itemizedlist>
<para>With the above in mind, the following is the sequence
of events for async request processing with a <interfacename>Callable</interfacename>:
(1) Controller returns a
<interfacename>Callable</interfacename>, (2) Spring MVC starts async processing
and submits the <interfacename>Callable</interfacename>
to a <interfacename>TaskExecutor</interfacename>
for processing in a separate thread, (3) the <classname>DispatcherServlet</classname>
and all Filter's exit the request processing thread but the response
remains open, (4) the <interfacename>Callable</interfacename> produces a result
and Spring MVC dispatches the request back to the Servlet container,
(5) the <classname>DispatcherServlet</classname> is invoked again and processing
resumes with the asynchronously produced result from the
<interfacename>Callable</interfacename>. The exact sequencing of (2),
(3), and (4) may vary depending on the speed of execution of the
concurrent threads.
</para>
<para>The sequence of events for async request processing with a
<classname>DeferredResult</classname> is the same in principal except
it's up to the application to produce the asynchronous result from some thread:
(1) Controller returns a <classname>DeferredResult</classname> and saves it
in some in-memory queue or list where it can be accessed,
(2) Spring MVC starts async processing, (3) the <classname>DispatcherServlet</classname>
and all configured Filter's exit the request processing thread but the response
remains open, (4) the application sets the <classname>DeferredResult</classname>
from some thread and Spring MVC dispatches the request back to the Servlet container,
(5) the <classname>DispatcherServlet</classname> is invoked again and processing
resumes with the asynchronously produced result.
</para>
<para>Explaining the motivation for async request processing, when or why to use it
is beyond the scope of this document. For further information you may wish to read
<linkxl:href="http://http://blog.springsource.org/2012/05/06/spring-mvc-3-2-preview-introducing-servlet-3-async-support/"> this blog post series</link>.
</para>
<sectionxml:id="mvc-ann-async-exceptions">
<title>Async Request Processing and Exception Handling</title>
<para>What happens if a <interfacename>Callable</interfacename> returned
from a controller method raises an Exception while being executed?
The effect is similar to what happens when any controller method raises
an exception. It is handled by a matching
<interfacename>@ExceptionHandler</interfacename> method in the same