Browse Source

Polish (minor) async support in filters

Issue: SPR-9895
pull/165/merge
Rossen Stoyanchev 13 years ago
parent
commit
d952da2338
  1. 13
      spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
  2. 10
      spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java
  3. 10
      spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java
  4. 13
      spring-web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java
  5. 74
      spring-web/src/main/java/org/springframework/web/filter/OncePerRequestFilter.java
  6. 6
      spring-web/src/main/java/org/springframework/web/filter/RequestContextFilter.java
  7. 13
      spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java

13
spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java

@ -169,13 +169,13 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter { @@ -169,13 +169,13 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
/**
* The default value is "true" so that the filter may re-bind the opened
* The default value is "false" so that the filter may re-bind the opened
* {@code Session} to each asynchronously dispatched thread and postpone
* closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldFilterAsyncDispatches() {
return true;
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
@Override
@ -187,7 +187,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter { @@ -187,7 +187,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
boolean participate = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
boolean isFirstRequest = !isAsyncDispatch(request);
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
String key = getAlreadyFilteredAttributeName();
if (isSingleSession()) {
@ -210,7 +210,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter { @@ -210,7 +210,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
else {
// deferred close mode
Assert.state(isLastRequestThread(request), "Deferred close mode is not supported on async dispatches");
Assert.state(!asyncManager.isConcurrentHandlingStarted(),
"Deferred close mode is not supported on async dispatches");
if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
// Do not modify deferred close: just set the participate flag.
participate = true;
@ -229,7 +230,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter { @@ -229,7 +230,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
// single session mode
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
if (isLastRequestThread(request)) {
if (!asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
closeSession(sessionHolder.getSession(), sessionFactory);
}

10
spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java

@ -102,13 +102,13 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter { @@ -102,13 +102,13 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
/**
* The default value is "true" so that the filter may re-bind the opened
* The default value is "false" so that the filter may re-bind the opened
* {@code Session} to each asynchronously dispatched thread and postpone
* closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldFilterAsyncDispatches() {
return true;
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
@Override
@ -120,7 +120,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter { @@ -120,7 +120,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
boolean participate = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
boolean isFirstRequest = !isAsyncDispatch(request);
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
String key = getAlreadyFilteredAttributeName();
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
@ -147,7 +147,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter { @@ -147,7 +147,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
if (!participate) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
if (isLastRequestThread(request)) {
if (!asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}

10
spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java

@ -126,13 +126,13 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter { @@ -126,13 +126,13 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
}
/**
* The default value is "true" so that the filter may re-bind the opened
* The default value is "false" so that the filter may re-bind the opened
* {@code EntityManager} to each asynchronously dispatched thread and postpone
* closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldFilterAsyncDispatches() {
return true;
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
@Override
@ -144,7 +144,7 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter { @@ -144,7 +144,7 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
boolean participate = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
boolean isFirstRequest = !isAsyncDispatch(request);
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
String key = getAlreadyFilteredAttributeName();
if (TransactionSynchronizationManager.hasResource(emf)) {
@ -175,7 +175,7 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter { @@ -175,7 +175,7 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
if (!participate) {
EntityManagerHolder emHolder = (EntityManagerHolder)
TransactionSynchronizationManager.unbindResource(emf);
if (isLastRequestThread(request)) {
if (!asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter");
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
}

13
spring-web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java

@ -32,6 +32,8 @@ import javax.servlet.http.HttpSession; @@ -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 @@ -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 @@ -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 @@ -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));
}
}

74
spring-web/src/main/java/org/springframework/web/filter/OncePerRequestFilter.java

@ -25,6 +25,7 @@ import javax.servlet.ServletResponse; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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.
*/

6
spring-web/src/main/java/org/springframework/web/filter/RequestContextFilter.java

@ -71,12 +71,12 @@ public class RequestContextFilter extends OncePerRequestFilter { @@ -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

13
spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java

@ -32,6 +32,8 @@ import javax.servlet.http.HttpServletResponseWrapper; @@ -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 { @@ -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 { @@ -74,7 +77,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
filterChain.doFilter(request, response);
if (isLastRequestThread(request)) {
if (!asyncManager.isConcurrentHandlingStarted()) {
updateResponse(request, response);
}
}

Loading…
Cancel
Save