We saw in the last tutorial, how to use CallableProcessingInterceptor to integrate more deeply with async processing lifecycle.
To have similar lifecycle interception around user defined 'DeferredResult' processing, we can register DeferredResultProcessingInterceptor
Example
Creating the DeferredResultProcessingInterceptor
package com.logicbig.example;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
public class MyDeferredResultProcessingInterceptor implements
DeferredResultProcessingInterceptor {
@Override
public <T> void beforeConcurrentHandling (NativeWebRequest request,
DeferredResult<T> deferredResult)
throws Exception {
System.out.println("deferredInterceptor#beforeConcurrentHandler called." +
"Thread: " + Thread.currentThread().getName());
}
@Override
public <T> void preProcess (NativeWebRequest request,
DeferredResult<T> deferredResult) throws Exception {
System.out.println("deferredInterceptor#preProcess called." +
"Thread: " + Thread.currentThread().getName());
}
@Override
public <T> void postProcess (NativeWebRequest request,
DeferredResult<T> deferredResult,
Object concurrentResult) throws Exception {
System.out.println("deferredInterceptor#postProcess called." +
"Thread: " + Thread.currentThread().getName());
}
@Override
public <T> boolean handleTimeout (NativeWebRequest request,
DeferredResult<T> deferredResult)
throws Exception {
System.out.println("deferredInterceptor#handleTimeout called." +
"Thread: " + Thread.currentThread().getName());
return false;
}
@Override
public <T> void afterCompletion (NativeWebRequest request,
DeferredResult<T> deferredResult)
throws Exception {
System.out.println("deferredInterceptor#afterCompletion called." +
"Thread: " + Thread.currentThread().getName());
}
}
Registering the interceptor
Similar to our last tutorial example, We can register the above interceptor in the HandlerInterceptor#preHandle method using WebAsyncManager:
package com.logicbig.example;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyAsyncHandlerInterceptor extends HandlerInterceptorAdapter {
private static final Object DEFERRED_INTERCEPTOR_KEY = new Object();
@Override
public boolean preHandle (HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("interceptor#preHandle called." +
" Thread: " + Thread.currentThread()
.getName());
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerDeferredResultInterceptor(DEFERRED_INTERCEPTOR_KEY,
new MyDeferredResultProcessingInterceptor());
return true;
}
.......
}
The Controller:
package com.logicbig.example;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;
@Controller
public class MyWebController {
@RequestMapping("/")
@ResponseBody
public DeferredResult<String> handleTestRequest () {
System.out.println("controller#handler called. Thread: " +
Thread.currentThread()
.getName());
final DeferredResult<String> deferredResult = new DeferredResult<>();
new Thread(() -> {
System.out.println("controller-deferred#async task started. Thread: " +
Thread.currentThread()
.getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
deferredResult.setResult("test async result");
System.out.println("controller-deferred#async task finished");
}).start();
System.out.println("controller#handler finished");
return deferredResult;
}
}
The main class is same as of our last example. On running the main class and accessing the application in the browser. We will have following output:
interceptor#preHandle called. Thread: http-nio-8080-exec-1
controller#handler called. Thread: http-nio-8080-exec-1
controller#handler finished
controller-deferred#async task started. Thread: Thread-3
deferredInterceptor#beforeConcurrentHandler called.Thread: http-nio-8080-exec-1
deferredInterceptor#preProcess called.Thread: http-nio-8080-exec-1
interceptor#afterConcurrentHandlingStarted called. Thread: http-nio-8080-exec-1
deferredInterceptor#postProcess called.Thread: Thread-3
controller-deferred#async task finished
interceptor#preHandle called. Thread: http-nio-8080-exec-2
interceptor#postHandle called.Thread: http-nio-8080-exec-2
interceptor#afterCompletion called Thread.: http-nio-8080-exec-2
deferredInterceptor#afterCompletion called.Thread: http-nio-8080-exec-2
This output is similar to the last example. In this case, the user is responsible to create his own thread for async processing in the controller method. User would normally call DeferredResult.setResult() at the end of the processing, which will cause DeferredInterceptor#postProcess invocation. To understand the all interception points, here's the flow diagram:
Example ProjectDependencies and Technologies Used: - Spring Boot 1.4.2.RELEASE
Corresponding Spring Version 4.3.4.RELEASE - Spring Boot Web Starter : Starter for building web, including RESTful, applications using Spring
MVC. Uses Tomcat as the default embedded container.
- JDK 1.8
- Maven 3.3.9
|