From 3cc94ae8b53c5d71c3cc4fc453e8569843dd2e26 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 25 May 2017 23:37:02 +0200 Subject: [PATCH] Consistently accept "taskExecutor" bean of type Executor (as stated in @EnableAsync's javadoc) Issue: SPR-15566 --- .../AsyncExecutionAspectSupport.java | 11 +++++- .../ScheduledAnnotationBeanPostProcessor.java | 2 + .../annotation/EnableAsyncTests.java | 38 +++++++++++++++++-- 3 files changed, 46 insertions(+), 5 deletions(-) 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 51f2afba3b6..f120147fe91 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -221,6 +221,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { return beanFactory.getBean(TaskExecutor.class); } catch (NoUniqueBeanDefinitionException ex) { + logger.debug("Could not find unique TaskExecutor bean", ex); try { return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); } @@ -234,8 +235,14 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { } catch (NoSuchBeanDefinitionException ex) { logger.debug("Could not find default TaskExecutor bean", ex); + try { + return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); + } + catch (NoSuchBeanDefinitionException ex2) { + logger.info("No task executor bean found for async processing: " + + "no bean of type TaskExecutor and no bean named 'taskExecutor' either"); + } // Giving up -> either using local default executor or none at all... - logger.info("No TaskExecutor bean found for async processing"); } } return null; diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java index 1399c12be10..9d70cac45ea 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java @@ -219,6 +219,7 @@ public class ScheduledAnnotationBeanPostProcessor this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, false)); } catch (NoUniqueBeanDefinitionException ex) { + logger.debug("Could not find unique TaskScheduler bean", ex); try { this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, true)); } @@ -239,6 +240,7 @@ public class ScheduledAnnotationBeanPostProcessor this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, false)); } catch (NoUniqueBeanDefinitionException ex2) { + logger.debug("Could not find unique ScheduledExecutorService bean", ex2); try { this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, true)); } 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 f6bc283f9f5..b0dc5523498 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 @@ -23,6 +23,7 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.Test; @@ -42,6 +43,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.core.Ordered; +import org.springframework.scheduling.concurrent.CustomizableThreadFactory; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; @@ -180,9 +182,23 @@ public class EnableAsyncTests { } @Test - public void customExecutorIsPropagated() throws InterruptedException { + public void customExecutorBean() throws InterruptedException { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(CustomExecutorAsyncConfig.class); + ctx.register(CustomExecutorBean.class); + ctx.refresh(); + + AsyncBean asyncBean = ctx.getBean(AsyncBean.class); + asyncBean.work(); + Thread.sleep(500); + assertThat(asyncBean.getThreadOfExecution().getName(), startsWith("Custom-")); + + ctx.close(); + } + + @Test + public void customExecutorConfig() throws InterruptedException { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(CustomExecutorConfig.class); ctx.refresh(); AsyncBean asyncBean = ctx.getBean(AsyncBean.class); @@ -381,7 +397,23 @@ public class EnableAsyncTests { @Configuration @EnableAsync - static class CustomExecutorAsyncConfig implements AsyncConfigurer { + static class CustomExecutorBean { + + @Bean + public AsyncBean asyncBean() { + return new AsyncBean(); + } + + @Bean + public Executor taskExecutor() { + return Executors.newSingleThreadExecutor(new CustomizableThreadFactory("Custom-")); + } + } + + + @Configuration + @EnableAsync + static class CustomExecutorConfig implements AsyncConfigurer { @Bean public AsyncBean asyncBean() {