Polish (minor) async support in filters
Issue: SPR-9895
This commit is contained in:
@@ -32,6 +32,8 @@ import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
@@ -178,13 +180,13 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value is "true" so that the filter may log a "before" message
|
||||
* The default value is "false" so that the filter may log a "before" message
|
||||
* at the start of request processing and an "after" message at the end from
|
||||
* when the last asynchronously dispatched thread is exiting.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldFilterAsyncDispatches() {
|
||||
return true;
|
||||
protected boolean shouldNotFilterAsyncDispatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +200,8 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
boolean isFirstRequest = !isAsyncDispatch(request);
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
|
||||
|
||||
if (isIncludePayload()) {
|
||||
if (isFirstRequest) {
|
||||
@@ -213,7 +216,7 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
finally {
|
||||
if (isLastRequestThread(request)) {
|
||||
if (!asyncManager.isConcurrentHandlingStarted()) {
|
||||
afterRequest(request, getAfterMessage(request));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
|
||||
/**
|
||||
@@ -36,7 +37,7 @@ import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
* as part of an {@linkplain javax.servlet.DispatcherType.ASYNC ASYNC} dispatch.
|
||||
* Sub-classes may decide whether to be invoked once per request or once per
|
||||
* request thread for as long as the same request is being processed.
|
||||
* See {@link #shouldFilterAsyncDispatches()}.
|
||||
* See {@link #shouldNotFilterAsyncDispatch()}.
|
||||
*
|
||||
* <p>The {@link #getAlreadyFilteredAttributeName} method determines how
|
||||
* to identify that a request is already filtered. The default implementation
|
||||
@@ -73,12 +74,13 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
boolean processAsyncRequestThread = isAsyncDispatch(httpRequest) && shouldFilterAsyncDispatches();
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
boolean processAsyncDispatch = asyncManager.hasConcurrentResult() && !shouldNotFilterAsyncDispatch();
|
||||
|
||||
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
|
||||
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
|
||||
|
||||
if ((hasAlreadyFilteredAttribute && (!processAsyncRequestThread)) || shouldNotFilter(httpRequest)) {
|
||||
if ((hasAlreadyFilteredAttribute && (!processAsyncDispatch)) || shouldNotFilter(httpRequest)) {
|
||||
|
||||
// Proceed without invoking this filter...
|
||||
filterChain.doFilter(request, response);
|
||||
@@ -90,7 +92,7 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
|
||||
doFilterInternal(httpRequest, httpResponse, filterChain);
|
||||
}
|
||||
finally {
|
||||
if (isLastRequestThread(httpRequest)) {
|
||||
if (!asyncManager.isConcurrentHandlingStarted()) {
|
||||
// Remove the "already filtered" request attribute for this request.
|
||||
request.removeAttribute(alreadyFilteredAttributeName);
|
||||
}
|
||||
@@ -128,60 +130,30 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to filter once per request or once per request thread. The dispatcher
|
||||
* type {@code javax.servlet.DispatcherType.ASYNC} introduced in Servlet 3.0
|
||||
* means a filter can be invoked in more than one thread (and exited) over the
|
||||
* course of a single request. Some filters only need to filter the initial
|
||||
* thread (e.g. request wrapping) while others may need to be invoked at least
|
||||
* once in each additional thread for example for setting up thread locals or
|
||||
* to perform final processing at the very end.
|
||||
* Whether to filter async dispatches, which occur in a different thread.
|
||||
* The dispatcher type {@code javax.servlet.DispatcherType.ASYNC} introduced
|
||||
* in Servlet 3.0 means a filter can be invoked in more than one thread (and
|
||||
* exited) over the course of a single request. Some filters only need to
|
||||
* filter the initial thread (e.g. request wrapping) while others may need
|
||||
* to be invoked at least once in each additional thread for example for
|
||||
* setting up thread locals or to perform final processing at the very end.
|
||||
* <p>Note that although a filter can be mapped to handle specific dispatcher
|
||||
* types via {@code web.xml} or in Java through the {@code ServletContext},
|
||||
* servlet containers may enforce different defaults with regards to dispatcher
|
||||
* types. This flag enforces the design intent of the filter.
|
||||
* <p>The default setting is "false", which means the filter will be invoked
|
||||
* once only per request and only on the initial request thread. If "true", the
|
||||
* filter will also be invoked once only on each additional thread.
|
||||
*
|
||||
* @see org.springframework.web.context.request.async.WebAsyncManager
|
||||
* servlet containers may enforce different defaults with regards to
|
||||
* dispatcher types. This flag enforces the design intent of the filter.
|
||||
* <p>The default setting is "true", which means the filter will not be
|
||||
* invoked during subsequent async dispatches. If "false", the filter will
|
||||
* be invoked during async dispatches with the same guarantees of being
|
||||
* invoked only once during a request within a single thread.
|
||||
*/
|
||||
protected boolean shouldFilterAsyncDispatches() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the request was dispatched to complete processing of results produced
|
||||
* in another thread. This aligns with the Servlet 3.0 dispatcher type
|
||||
* {@code javax.servlet.DispatcherType.ASYNC} and can be used by filters that
|
||||
* return "true" from {@link #shouldFilterAsyncDispatches()} to detect when
|
||||
* the filter is being invoked subsequently in additional thread(s).
|
||||
*
|
||||
* @see org.springframework.web.context.request.async.WebAsyncManager
|
||||
*/
|
||||
protected final boolean isAsyncDispatch(HttpServletRequest request) {
|
||||
return WebAsyncUtils.getAsyncManager(request).hasConcurrentResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this is the last thread processing the request. Note the returned
|
||||
* value may change from {@code true} to {@code false} if the method is
|
||||
* invoked before and after delegating to the next filter, since the next filter
|
||||
* or servlet may begin concurrent processing. Therefore this method is most
|
||||
* useful after delegation for final, end-of-request type processing.
|
||||
* @param request the current request
|
||||
* @return {@code true} if the response will be committed when the current
|
||||
* thread exits; {@code false} if the response will remain open.
|
||||
*
|
||||
* @see org.springframework.web.context.request.async.WebAsyncManager
|
||||
*/
|
||||
protected final boolean isLastRequestThread(HttpServletRequest request) {
|
||||
return (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted());
|
||||
protected boolean shouldNotFilterAsyncDispatch() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same contract as for <code>doFilter</code>, but guaranteed to be
|
||||
* just invoked once per request or once per request thread.
|
||||
* See {@link #shouldFilterAsyncDispatches()} for details.
|
||||
* just invoked once per request within a single request thread.
|
||||
* See {@link #shouldNotFilterAsyncDispatch()} for details.
|
||||
* <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
|
||||
* default ServletRequest and ServletResponse ones.
|
||||
*/
|
||||
|
||||
@@ -71,12 +71,12 @@ public class RequestContextFilter extends OncePerRequestFilter {
|
||||
|
||||
|
||||
/**
|
||||
* The default value is "true" in which case the filter will set up the request
|
||||
* The default value is "false" in which case the filter will set up the request
|
||||
* context in each asynchronously dispatched thread.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldFilterAsyncDispatches() {
|
||||
return true;
|
||||
protected boolean shouldNotFilterAsyncDispatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,6 +32,8 @@ import javax.servlet.http.HttpServletResponseWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
@@ -54,19 +56,20 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
|
||||
|
||||
/**
|
||||
* The default value is "true" so that the filter may delay the generation of
|
||||
* The default value is "false" so that the filter may delay the generation of
|
||||
* an ETag until the last asynchronously dispatched thread.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldFilterAsyncDispatches() {
|
||||
return true;
|
||||
protected boolean shouldNotFilterAsyncDispatch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
boolean isFirstRequest = !isAsyncDispatch(request);
|
||||
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
|
||||
|
||||
if (isFirstRequest) {
|
||||
response = new ShallowEtagResponseWrapper(response);
|
||||
@@ -74,7 +77,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
if (isLastRequestThread(request)) {
|
||||
if (!asyncManager.isConcurrentHandlingStarted()) {
|
||||
updateResponse(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user