Skip to content

Commit d952da2

Browse files
committed
Polish (minor) async support in filters
Issue: SPR-9895
1 parent f7ec738 commit d952da2

File tree

7 files changed

+59
-80
lines changed

7 files changed

+59
-80
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,13 @@ protected FlushMode getFlushMode() {
169169
}
170170

171171
/**
172-
* The default value is "true" so that the filter may re-bind the opened
172+
* The default value is "false" so that the filter may re-bind the opened
173173
* {@code Session} to each asynchronously dispatched thread and postpone
174174
* closing it until the very last asynchronous dispatch.
175175
*/
176176
@Override
177-
protected boolean shouldFilterAsyncDispatches() {
178-
return true;
177+
protected boolean shouldNotFilterAsyncDispatch() {
178+
return false;
179179
}
180180

181181
@Override
@@ -187,7 +187,7 @@ protected void doFilterInternal(
187187
boolean participate = false;
188188

189189
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
190-
boolean isFirstRequest = !isAsyncDispatch(request);
190+
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
191191
String key = getAlreadyFilteredAttributeName();
192192

193193
if (isSingleSession()) {
@@ -210,7 +210,8 @@ protected void doFilterInternal(
210210
}
211211
else {
212212
// deferred close mode
213-
Assert.state(isLastRequestThread(request), "Deferred close mode is not supported on async dispatches");
213+
Assert.state(!asyncManager.isConcurrentHandlingStarted(),
214+
"Deferred close mode is not supported on async dispatches");
214215
if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
215216
// Do not modify deferred close: just set the participate flag.
216217
participate = true;
@@ -229,7 +230,7 @@ protected void doFilterInternal(
229230
// single session mode
230231
SessionHolder sessionHolder =
231232
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
232-
if (isLastRequestThread(request)) {
233+
if (!asyncManager.isConcurrentHandlingStarted()) {
233234
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
234235
closeSession(sessionHolder.getSession(), sessionFactory);
235236
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,13 @@ protected String getSessionFactoryBeanName() {
102102
}
103103

104104
/**
105-
* The default value is "true" so that the filter may re-bind the opened
105+
* The default value is "false" so that the filter may re-bind the opened
106106
* {@code Session} to each asynchronously dispatched thread and postpone
107107
* closing it until the very last asynchronous dispatch.
108108
*/
109109
@Override
110-
protected boolean shouldFilterAsyncDispatches() {
111-
return true;
110+
protected boolean shouldNotFilterAsyncDispatch() {
111+
return false;
112112
}
113113

114114
@Override
@@ -120,7 +120,7 @@ protected void doFilterInternal(
120120
boolean participate = false;
121121

122122
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
123-
boolean isFirstRequest = !isAsyncDispatch(request);
123+
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
124124
String key = getAlreadyFilteredAttributeName();
125125

126126
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
@@ -147,7 +147,7 @@ protected void doFilterInternal(
147147
if (!participate) {
148148
SessionHolder sessionHolder =
149149
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
150-
if (isLastRequestThread(request)) {
150+
if (!asyncManager.isConcurrentHandlingStarted()) {
151151
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
152152
SessionFactoryUtils.closeSession(sessionHolder.getSession());
153153
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,13 @@ protected String getPersistenceUnitName() {
126126
}
127127

128128
/**
129-
* The default value is "true" so that the filter may re-bind the opened
129+
* The default value is "false" so that the filter may re-bind the opened
130130
* {@code EntityManager} to each asynchronously dispatched thread and postpone
131131
* closing it until the very last asynchronous dispatch.
132132
*/
133133
@Override
134-
protected boolean shouldFilterAsyncDispatches() {
135-
return true;
134+
protected boolean shouldNotFilterAsyncDispatch() {
135+
return false;
136136
}
137137

138138
@Override
@@ -144,7 +144,7 @@ protected void doFilterInternal(
144144
boolean participate = false;
145145

146146
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
147-
boolean isFirstRequest = !isAsyncDispatch(request);
147+
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
148148
String key = getAlreadyFilteredAttributeName();
149149

150150
if (TransactionSynchronizationManager.hasResource(emf)) {
@@ -175,7 +175,7 @@ protected void doFilterInternal(
175175
if (!participate) {
176176
EntityManagerHolder emHolder = (EntityManagerHolder)
177177
TransactionSynchronizationManager.unbindResource(emf);
178-
if (isLastRequestThread(request)) {
178+
if (!asyncManager.isConcurrentHandlingStarted()) {
179179
logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter");
180180
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
181181
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
import org.springframework.util.Assert;
3434
import org.springframework.util.StringUtils;
35+
import org.springframework.web.context.request.async.WebAsyncManager;
36+
import org.springframework.web.context.request.async.WebAsyncUtils;
3537
import org.springframework.web.util.WebUtils;
3638

3739
/**
@@ -178,13 +180,13 @@ public void setAfterMessageSuffix(String afterMessageSuffix) {
178180
}
179181

180182
/**
181-
* The default value is "true" so that the filter may log a "before" message
183+
* The default value is "false" so that the filter may log a "before" message
182184
* at the start of request processing and an "after" message at the end from
183185
* when the last asynchronously dispatched thread is exiting.
184186
*/
185187
@Override
186-
protected boolean shouldFilterAsyncDispatches() {
187-
return true;
188+
protected boolean shouldNotFilterAsyncDispatch() {
189+
return false;
188190
}
189191

190192
/**
@@ -198,7 +200,8 @@ protected boolean shouldFilterAsyncDispatches() {
198200
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
199201
throws ServletException, IOException {
200202

201-
boolean isFirstRequest = !isAsyncDispatch(request);
203+
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
204+
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
202205

203206
if (isIncludePayload()) {
204207
if (isFirstRequest) {
@@ -213,7 +216,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
213216
filterChain.doFilter(request, response);
214217
}
215218
finally {
216-
if (isLastRequestThread(request)) {
219+
if (!asyncManager.isConcurrentHandlingStarted()) {
217220
afterRequest(request, getAfterMessage(request));
218221
}
219222
}

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

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import javax.servlet.http.HttpServletRequest;
2626
import javax.servlet.http.HttpServletResponse;
2727

28+
import org.springframework.web.context.request.async.WebAsyncManager;
2829
import org.springframework.web.context.request.async.WebAsyncUtils;
2930

3031
/**
@@ -36,7 +37,7 @@
3637
* as part of an {@linkplain javax.servlet.DispatcherType.ASYNC ASYNC} dispatch.
3738
* Sub-classes may decide whether to be invoked once per request or once per
3839
* request thread for as long as the same request is being processed.
39-
* See {@link #shouldFilterAsyncDispatches()}.
40+
* See {@link #shouldNotFilterAsyncDispatch()}.
4041
*
4142
* <p>The {@link #getAlreadyFilteredAttributeName} method determines how
4243
* to identify that a request is already filtered. The default implementation
@@ -73,12 +74,13 @@ public final void doFilter(ServletRequest request, ServletResponse response, Fil
7374
HttpServletRequest httpRequest = (HttpServletRequest) request;
7475
HttpServletResponse httpResponse = (HttpServletResponse) response;
7576

76-
boolean processAsyncRequestThread = isAsyncDispatch(httpRequest) && shouldFilterAsyncDispatches();
77+
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
78+
boolean processAsyncDispatch = asyncManager.hasConcurrentResult() && !shouldNotFilterAsyncDispatch();
7779

7880
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
7981
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
8082

81-
if ((hasAlreadyFilteredAttribute && (!processAsyncRequestThread)) || shouldNotFilter(httpRequest)) {
83+
if ((hasAlreadyFilteredAttribute && (!processAsyncDispatch)) || shouldNotFilter(httpRequest)) {
8284

8385
// Proceed without invoking this filter...
8486
filterChain.doFilter(request, response);
@@ -90,7 +92,7 @@ public final void doFilter(ServletRequest request, ServletResponse response, Fil
9092
doFilterInternal(httpRequest, httpResponse, filterChain);
9193
}
9294
finally {
93-
if (isLastRequestThread(httpRequest)) {
95+
if (!asyncManager.isConcurrentHandlingStarted()) {
9496
// Remove the "already filtered" request attribute for this request.
9597
request.removeAttribute(alreadyFilteredAttributeName);
9698
}
@@ -128,60 +130,30 @@ protected boolean shouldNotFilter(HttpServletRequest request) throws ServletExce
128130
}
129131

130132
/**
131-
* Whether to filter once per request or once per request thread. The dispatcher
132-
* type {@code javax.servlet.DispatcherType.ASYNC} introduced in Servlet 3.0
133-
* means a filter can be invoked in more than one thread (and exited) over the
134-
* course of a single request. Some filters only need to filter the initial
135-
* thread (e.g. request wrapping) while others may need to be invoked at least
136-
* once in each additional thread for example for setting up thread locals or
137-
* to perform final processing at the very end.
133+
* Whether to filter async dispatches, which occur in a different thread.
134+
* The dispatcher type {@code javax.servlet.DispatcherType.ASYNC} introduced
135+
* in Servlet 3.0 means a filter can be invoked in more than one thread (and
136+
* exited) over the course of a single request. Some filters only need to
137+
* filter the initial thread (e.g. request wrapping) while others may need
138+
* to be invoked at least once in each additional thread for example for
139+
* setting up thread locals or to perform final processing at the very end.
138140
* <p>Note that although a filter can be mapped to handle specific dispatcher
139141
* types via {@code web.xml} or in Java through the {@code ServletContext},
140-
* servlet containers may enforce different defaults with regards to dispatcher
141-
* types. This flag enforces the design intent of the filter.
142-
* <p>The default setting is "false", which means the filter will be invoked
143-
* once only per request and only on the initial request thread. If "true", the
144-
* filter will also be invoked once only on each additional thread.
145-
*
146-
* @see org.springframework.web.context.request.async.WebAsyncManager
142+
* servlet containers may enforce different defaults with regards to
143+
* dispatcher types. This flag enforces the design intent of the filter.
144+
* <p>The default setting is "true", which means the filter will not be
145+
* invoked during subsequent async dispatches. If "false", the filter will
146+
* be invoked during async dispatches with the same guarantees of being
147+
* invoked only once during a request within a single thread.
147148
*/
148-
protected boolean shouldFilterAsyncDispatches() {
149-
return false;
150-
}
151-
152-
/**
153-
* Whether the request was dispatched to complete processing of results produced
154-
* in another thread. This aligns with the Servlet 3.0 dispatcher type
155-
* {@code javax.servlet.DispatcherType.ASYNC} and can be used by filters that
156-
* return "true" from {@link #shouldFilterAsyncDispatches()} to detect when
157-
* the filter is being invoked subsequently in additional thread(s).
158-
*
159-
* @see org.springframework.web.context.request.async.WebAsyncManager
160-
*/
161-
protected final boolean isAsyncDispatch(HttpServletRequest request) {
162-
return WebAsyncUtils.getAsyncManager(request).hasConcurrentResult();
163-
}
164-
165-
/**
166-
* Whether this is the last thread processing the request. Note the returned
167-
* value may change from {@code true} to {@code false} if the method is
168-
* invoked before and after delegating to the next filter, since the next filter
169-
* or servlet may begin concurrent processing. Therefore this method is most
170-
* useful after delegation for final, end-of-request type processing.
171-
* @param request the current request
172-
* @return {@code true} if the response will be committed when the current
173-
* thread exits; {@code false} if the response will remain open.
174-
*
175-
* @see org.springframework.web.context.request.async.WebAsyncManager
176-
*/
177-
protected final boolean isLastRequestThread(HttpServletRequest request) {
178-
return (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted());
149+
protected boolean shouldNotFilterAsyncDispatch() {
150+
return true;
179151
}
180152

181153
/**
182154
* Same contract as for <code>doFilter</code>, but guaranteed to be
183-
* just invoked once per request or once per request thread.
184-
* See {@link #shouldFilterAsyncDispatches()} for details.
155+
* just invoked once per request within a single request thread.
156+
* See {@link #shouldNotFilterAsyncDispatch()} for details.
185157
* <p>Provides HttpServletRequest and HttpServletResponse arguments instead of the
186158
* default ServletRequest and ServletResponse ones.
187159
*/

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ public void setThreadContextInheritable(boolean threadContextInheritable) {
7171

7272

7373
/**
74-
* The default value is "true" in which case the filter will set up the request
74+
* The default value is "false" in which case the filter will set up the request
7575
* context in each asynchronously dispatched thread.
7676
*/
7777
@Override
78-
protected boolean shouldFilterAsyncDispatches() {
79-
return true;
78+
protected boolean shouldNotFilterAsyncDispatch() {
79+
return false;
8080
}
8181

8282
@Override

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import org.springframework.util.Assert;
3333
import org.springframework.util.DigestUtils;
3434
import org.springframework.util.FileCopyUtils;
35+
import org.springframework.web.context.request.async.WebAsyncManager;
36+
import org.springframework.web.context.request.async.WebAsyncUtils;
3537
import org.springframework.web.util.WebUtils;
3638

3739
/**
@@ -54,27 +56,28 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
5456

5557

5658
/**
57-
* The default value is "true" so that the filter may delay the generation of
59+
* The default value is "false" so that the filter may delay the generation of
5860
* an ETag until the last asynchronously dispatched thread.
5961
*/
6062
@Override
61-
protected boolean shouldFilterAsyncDispatches() {
62-
return true;
63+
protected boolean shouldNotFilterAsyncDispatch() {
64+
return false;
6365
}
6466

6567
@Override
6668
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
6769
throws ServletException, IOException {
6870

69-
boolean isFirstRequest = !isAsyncDispatch(request);
71+
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
72+
boolean isFirstRequest = !asyncManager.hasConcurrentResult();
7073

7174
if (isFirstRequest) {
7275
response = new ShallowEtagResponseWrapper(response);
7376
}
7477

7578
filterChain.doFilter(request, response);
7679

77-
if (isLastRequestThread(request)) {
80+
if (!asyncManager.isConcurrentHandlingStarted()) {
7881
updateResponse(request, response);
7982
}
8083
}

0 commit comments

Comments
 (0)