Consistently accept "taskExecutor" bean of type Executor (as stated in @EnableAsync's javadoc)
Issue: SPR-15566
This commit is contained in:
		
							parent
							
								
									0287a74d69
								
							
						
					
					
						commit
						3cc94ae8b5
					
				|  | @ -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"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with 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); | 				return beanFactory.getBean(TaskExecutor.class); | ||||||
| 			} | 			} | ||||||
| 			catch (NoUniqueBeanDefinitionException ex) { | 			catch (NoUniqueBeanDefinitionException ex) { | ||||||
|  | 				logger.debug("Could not find unique TaskExecutor bean", ex); | ||||||
| 				try { | 				try { | ||||||
| 					return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); | 					return beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class); | ||||||
| 				} | 				} | ||||||
|  | @ -234,8 +235,14 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { | ||||||
| 			} | 			} | ||||||
| 			catch (NoSuchBeanDefinitionException ex) { | 			catch (NoSuchBeanDefinitionException ex) { | ||||||
| 				logger.debug("Could not find default TaskExecutor bean", 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... | 				// Giving up -> either using local default executor or none at all... | ||||||
| 				logger.info("No TaskExecutor bean found for async processing"); |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return null; | 		return null; | ||||||
|  |  | ||||||
|  | @ -219,6 +219,7 @@ public class ScheduledAnnotationBeanPostProcessor | ||||||
| 				this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, false)); | 				this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, false)); | ||||||
| 			} | 			} | ||||||
| 			catch (NoUniqueBeanDefinitionException ex) { | 			catch (NoUniqueBeanDefinitionException ex) { | ||||||
|  | 				logger.debug("Could not find unique TaskScheduler bean", ex); | ||||||
| 				try { | 				try { | ||||||
| 					this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, true)); | 					this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, true)); | ||||||
| 				} | 				} | ||||||
|  | @ -239,6 +240,7 @@ public class ScheduledAnnotationBeanPostProcessor | ||||||
| 					this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, false)); | 					this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, false)); | ||||||
| 				} | 				} | ||||||
| 				catch (NoUniqueBeanDefinitionException ex2) { | 				catch (NoUniqueBeanDefinitionException ex2) { | ||||||
|  | 					logger.debug("Could not find unique ScheduledExecutorService bean", ex2); | ||||||
| 					try { | 					try { | ||||||
| 						this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, true)); | 						this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, true)); | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ import java.lang.annotation.Target; | ||||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||||
| import java.util.concurrent.ExecutionException; | import java.util.concurrent.ExecutionException; | ||||||
| import java.util.concurrent.Executor; | import java.util.concurrent.Executor; | ||||||
|  | import java.util.concurrent.Executors; | ||||||
| import java.util.concurrent.Future; | import java.util.concurrent.Future; | ||||||
| 
 | 
 | ||||||
| import org.junit.Test; | 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.Configuration; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.core.Ordered; | import org.springframework.core.Ordered; | ||||||
|  | import org.springframework.scheduling.concurrent.CustomizableThreadFactory; | ||||||
| import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
| import org.springframework.util.ReflectionUtils; | import org.springframework.util.ReflectionUtils; | ||||||
|  | @ -180,9 +182,23 @@ public class EnableAsyncTests { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void customExecutorIsPropagated() throws InterruptedException { | 	public void customExecutorBean() throws InterruptedException { | ||||||
| 		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); | 		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(); | 		ctx.refresh(); | ||||||
| 
 | 
 | ||||||
| 		AsyncBean asyncBean = ctx.getBean(AsyncBean.class); | 		AsyncBean asyncBean = ctx.getBean(AsyncBean.class); | ||||||
|  | @ -381,7 +397,23 @@ public class EnableAsyncTests { | ||||||
| 
 | 
 | ||||||
| 	@Configuration | 	@Configuration | ||||||
| 	@EnableAsync | 	@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 | 		@Bean | ||||||
| 		public AsyncBean asyncBean() { | 		public AsyncBean asyncBean() { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue