diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java index 51b76a23b14a..37b67bd30f0a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java @@ -41,6 +41,8 @@ import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; +import org.springframework.util.StringValueResolver; +import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.function.SingletonSupplier; /** @@ -56,6 +58,7 @@ * @author Chris Beams * @author Juergen Hoeller * @author Stephane Nicoll + * @author He Bo * @since 3.1.2 */ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { @@ -80,6 +83,8 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { @Nullable private BeanFactory beanFactory; + @Nullable + private StringValueResolver stringValueResolver; /** * Create a new instance with a default {@link AsyncUncaughtExceptionHandler}. @@ -150,6 +155,9 @@ public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; + if (beanFactory instanceof ConfigurableBeanFactory configurableBeanFactory) { + this.stringValueResolver = new EmbeddedValueResolver(configurableBeanFactory); + } } @@ -163,6 +171,9 @@ protected AsyncTaskExecutor determineAsyncExecutor(Method method) { if (executor == null) { Executor targetExecutor; String qualifier = getExecutorQualifier(method); + if (this.stringValueResolver != null && StringUtils.hasLength(qualifier)) { + qualifier = this.stringValueResolver.resolveStringValue(qualifier); + } if (StringUtils.hasLength(qualifier)) { targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier); } @@ -206,10 +217,6 @@ protected Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, Stri throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() + " to access qualified executor '" + qualifier + "'"); } - if (beanFactory instanceof ConfigurableBeanFactory configurableBeanFactory) { - EmbeddedValueResolver embeddedValueResolver = new EmbeddedValueResolver(configurableBeanFactory); - qualifier = embeddedValueResolver.resolveStringValue(qualifier); - } return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier); } diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java index f19c945b08f0..b2a1e1140e34 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java @@ -146,6 +146,9 @@ public void withAsyncBeanWithExecutorQualifiedByExpressionOrPlaceholder() throws Future workerThread2 = asyncBean.myWork2(); assertThat(workerThread2.get().getName()).startsWith("myExecutor2-"); + + Future workerThread3 = asyncBean.defaultExecutor(); + assertThat(workerThread3.get().getName()).startsWith("SimpleAsyncTaskExecutor"); } finally { System.clearProperty("myExecutor"); @@ -382,6 +385,11 @@ public Future myWork1() { public Future myWork2() { return new AsyncResult<>(Thread.currentThread()); } + + @Async("${my.app.targetExecutor:}") + public Future defaultExecutor() { + return new AsyncResult<>(Thread.currentThread()); + } }