Consistent result synchronization in WebAsyncManager

Issue: SPR-16571

(cherry picked from commit cf74b1b)
This commit is contained in:
Juergen Hoeller
2018-03-09 09:03:15 +01:00
parent 1bde920cce
commit eeeb0a6546

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
@@ -50,6 +50,7 @@ import org.springframework.web.util.UrlPathHelper;
* detected via {@link #hasConcurrentResult()}.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.2
* @see org.springframework.web.context.request.AsyncWebRequestInterceptor
* @see org.springframework.web.servlet.AsyncHandlerInterceptor
@@ -75,9 +76,9 @@ public final class WebAsyncManager {
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(this.getClass().getSimpleName());
private Object concurrentResult = RESULT_NONE;
private volatile Object concurrentResult = RESULT_NONE;
private Object[] concurrentResultContext;
private volatile Object[] concurrentResultContext;
private final Map<Object, CallableProcessingInterceptor> callableInterceptors =
new LinkedHashMap<Object, CallableProcessingInterceptor>();
@@ -133,7 +134,7 @@ public final class WebAsyncManager {
* processing of the concurrent result.
*/
public boolean isConcurrentHandlingStarted() {
return ((this.asyncWebRequest != null) && this.asyncWebRequest.isAsyncStarted());
return (this.asyncWebRequest != null && this.asyncWebRequest.isAsyncStarted());
}
/**
@@ -165,7 +166,7 @@ public final class WebAsyncManager {
/**
* Get the {@link CallableProcessingInterceptor} registered under the given key.
* @param key the key
* @return the interceptor registered under that key or {@code null}
* @return the interceptor registered under that key, or {@code null} if none
*/
public CallableProcessingInterceptor getCallableInterceptor(Object key) {
return this.callableInterceptors.get(key);
@@ -174,7 +175,7 @@ public final class WebAsyncManager {
/**
* Get the {@link DeferredResultProcessingInterceptor} registered under the given key.
* @param key the key
* @return the interceptor registered under that key or {@code null}
* @return the interceptor registered under that key, or {@code null} if none
*/
public DeferredResultProcessingInterceptor getDeferredResultInterceptor(Object key) {
return this.deferredResultInterceptors.get(key);
@@ -233,8 +234,10 @@ public final class WebAsyncManager {
* {@linkplain #getConcurrentResultContext() concurrentResultContext}.
*/
public void clearConcurrentResult() {
this.concurrentResult = RESULT_NONE;
this.concurrentResultContext = null;
synchronized (WebAsyncManager.this) {
this.concurrentResult = RESULT_NONE;
this.concurrentResultContext = null;
}
}
/**
@@ -265,7 +268,9 @@ public final class WebAsyncManager {
* via {@link #getConcurrentResultContext()}
* @throws Exception if concurrent processing failed to start
*/
public void startCallableProcessing(final WebAsyncTask<?> webAsyncTask, Object... processingContext) throws Exception {
public void startCallableProcessing(final WebAsyncTask<?> webAsyncTask, Object... processingContext)
throws Exception {
Assert.notNull(webAsyncTask, "WebAsyncTask must not be null");
Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");
@@ -346,7 +351,7 @@ public final class WebAsyncManager {
private void setConcurrentResultAndDispatch(Object result) {
synchronized (WebAsyncManager.this) {
if (hasConcurrentResult()) {
if (this.concurrentResult != RESULT_NONE) {
return;
}
this.concurrentResult = result;
@@ -361,7 +366,6 @@ public final class WebAsyncManager {
logger.debug("Concurrent result value [" + this.concurrentResult +
"] - dispatching request to resume processing");
}
this.asyncWebRequest.dispatch();
}
@@ -445,8 +449,10 @@ public final class WebAsyncManager {
}
private void startAsyncProcessing(Object[] processingContext) {
clearConcurrentResult();
this.concurrentResultContext = processingContext;
synchronized (WebAsyncManager.this) {
this.concurrentResult = RESULT_NONE;
this.concurrentResultContext = processingContext;
}
this.asyncWebRequest.startAsync();
if (logger.isDebugEnabled()) {