From eeeb0a65460b826b95c119791a3990e4836e78f1 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 9 Mar 2018 09:03:15 +0100 Subject: [PATCH] Consistent result synchronization in WebAsyncManager Issue: SPR-16571 (cherry picked from commit cf74b1b) --- .../request/async/WebAsyncManager.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java index 92fcb48a63..6bcbbdcc4f 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java @@ -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 callableInterceptors = new LinkedHashMap(); @@ -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()) {