Add interceptors for async processing
This change introduces two new interceptors with callback methods for concurrent request handling. These interfaces are CallableProcessingInterceptor and DeferredResultProcessingInterceptor. Unlike a HandlerInterceptor, and its AsyncHandlerInterceptor sub-type, which intercepts the invocation of a handler in he main request processing thread, the two new interfaces are aimed at intercepting the asynchronous execution of a Callable or a DeferredResult. This allows for the registration of thread initialization logic in the case of Callable executed with an AsyncTaskExecutor, or for centralized tracking of the completion and/or expiration of a DeferredResult.
This commit is contained in:
@@ -19,18 +19,19 @@ package org.springframework.web.servlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
/**
|
||||
* Extends {@code HandlerInterceptor} with a callback method invoked during
|
||||
* asynchronous request handling.
|
||||
*
|
||||
* <p>When a handler starts asynchronous request handling, the DispatcherServlet
|
||||
* exits without invoking {@code postHandle} and {@code afterCompletion}, as it
|
||||
* normally does, since the results of request handling (e.g. ModelAndView) are
|
||||
* not available in the current thread and handling is not yet complete.
|
||||
* In such scenarios, the
|
||||
* normally does, since the results of request handling (e.g. ModelAndView)
|
||||
* will. be produced concurrently in another thread. In such scenarios,
|
||||
* {@link #afterConcurrentHandlingStarted(HttpServletRequest, HttpServletResponse)}
|
||||
* method is invoked instead allowing implementations to perform tasks such as
|
||||
* cleaning up thread bound attributes.
|
||||
* is invoked instead allowing implementations to perform tasks such as cleaning
|
||||
* up thread bound attributes.
|
||||
*
|
||||
* <p>When asynchronous handling completes, the request is dispatched to the
|
||||
* container for further processing. At this stage the DispatcherServlet invokes
|
||||
@@ -40,20 +41,26 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* @since 3.2
|
||||
*
|
||||
* @see org.springframework.web.context.request.async.WebAsyncManager
|
||||
* @see org.springframework.web.context.request.async.CallableProcessingInterceptor
|
||||
* @see org.springframework.web.context.request.async.DeferredResultProcessingInterceptor
|
||||
*/
|
||||
public interface AsyncHandlerInterceptor extends HandlerInterceptor {
|
||||
|
||||
/**
|
||||
* Called instead of {@code postHandle} and {@code afterCompletion}, when the
|
||||
* a handler is being executed concurrently. Implementations may use the provided
|
||||
* request and response but should avoid modifying them in ways that would
|
||||
* conflict with the concurrent execution of the handler. A typical use of
|
||||
* this method would be to clean thread local variables.
|
||||
* Called instead of {@code postHandle} and {@code afterCompletion}, when
|
||||
* the a handler is being executed concurrently. Implementations may use the
|
||||
* provided request and response but should avoid modifying them in ways
|
||||
* that would conflict with the concurrent execution of the handler. A
|
||||
* typical use of this method would be to clean thread local variables.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
* @param handler handler that started async execution, for type and/or instance examination
|
||||
* @param handler handler (or {@link HandlerMethod}) that started async
|
||||
* execution, for type and/or instance examination
|
||||
* @throws Exception in case of errors
|
||||
*/
|
||||
void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler);
|
||||
void afterConcurrentHandlingStarted(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception;
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -44,12 +45,13 @@ import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager.WebAsyncThreadInitializer;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.context.support.ServletRequestHandledEvent;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.context.support.XmlWebApplicationContext;
|
||||
@@ -909,7 +911,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
|
||||
initContextHolders(request, localeContext, requestAttributes);
|
||||
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
asyncManager.registerAsyncThreadInitializer(this.getClass().getName(), createAsyncThreadInitializer(request));
|
||||
asyncManager.registerCallableInterceptor(this.getClass().getName(), createRequestBindingInterceptor(request));
|
||||
|
||||
try {
|
||||
doService(request, response);
|
||||
@@ -992,13 +994,15 @@ public abstract class FrameworkServlet extends HttpServletBean {
|
||||
}
|
||||
}
|
||||
|
||||
private WebAsyncThreadInitializer createAsyncThreadInitializer(final HttpServletRequest request) {
|
||||
private CallableProcessingInterceptor createRequestBindingInterceptor(final HttpServletRequest request) {
|
||||
|
||||
return new WebAsyncThreadInitializer() {
|
||||
public void initialize() {
|
||||
return new CallableProcessingInterceptor() {
|
||||
|
||||
public void preProcess(NativeWebRequest webRequest, Callable<?> task) {
|
||||
initContextHolders(request, buildLocaleContext(request), new ServletRequestAttributes(request));
|
||||
}
|
||||
public void reset() {
|
||||
|
||||
public void postProcess(NativeWebRequest webRequest, Callable<?> task, Object concurrentResult) {
|
||||
resetContextHolders(request, null, null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.web.servlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
/**
|
||||
* Workflow interface that allows for customized handler execution chains.
|
||||
* Applications can register any number of existing or custom interceptors
|
||||
@@ -36,8 +38,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* {@code postHandle} and {@code afterCompletion} callbacks. When concurrent
|
||||
* handler execution completes, the request is dispatched back in order to
|
||||
* proceed with rendering the model and all methods of this contract are invoked
|
||||
* again. For further options and comments see
|
||||
* {@code org.springframework.web.servlet.HandlerInterceptor}
|
||||
* again. For further options and details see
|
||||
* {@code org.springframework.web.servlet.AsyncHandlerInterceptor}
|
||||
*
|
||||
* <p>Typically an interceptor chain is defined per HandlerMapping bean,
|
||||
* sharing its granularity. To be able to apply a certain interceptor chain
|
||||
@@ -100,7 +102,8 @@ public interface HandlerInterceptor {
|
||||
* getting applied in inverse order of the execution chain.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param handler chosen handler to execute, for type and/or instance examination
|
||||
* @param handler handler (or {@link HandlerMethod}) that started async
|
||||
* execution, for type and/or instance examination
|
||||
* @param modelAndView the <code>ModelAndView</code> that the handler returned
|
||||
* (can also be <code>null</code>)
|
||||
* @throws Exception in case of errors
|
||||
@@ -120,7 +123,8 @@ public interface HandlerInterceptor {
|
||||
* the last to be invoked.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param handler chosen handler to execute, for type and/or instance examination
|
||||
* @param handler handler (or {@link HandlerMethod}) that started async
|
||||
* execution, for type and/or instance examination
|
||||
* @param ex exception thrown on handler execution, if any
|
||||
* @throws Exception in case of errors
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,7 @@ package org.springframework.web.servlet.handler;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
* @author Juergen Hoeller
|
||||
* @since 05.12.2003
|
||||
*/
|
||||
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
|
||||
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
|
||||
|
||||
/**
|
||||
* This implementation always returns <code>true</code>.
|
||||
@@ -55,4 +55,12 @@ public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
|
||||
throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation is empty.
|
||||
*/
|
||||
public void afterConcurrentHandlingStarted(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user