Browse Source

AsyncAnnotationBeanPostProcessor tries to find TaskExecutor by type/name

Issue: SPR-13248
pull/840/merge
Juergen Hoeller 9 years ago
parent
commit
c3e57dd245
  1. 46
      spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java
  2. 3
      spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
  3. 57
      spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessorTests.java

46
spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -19,10 +19,15 @@ package org.springframework.scheduling.annotation; @@ -19,10 +19,15 @@ package org.springframework.scheduling.annotation;
import java.lang.annotation.Annotation;
import java.util.concurrent.Executor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.Assert;
@ -54,10 +59,21 @@ import org.springframework.util.Assert; @@ -54,10 +59,21 @@ import org.springframework.util.Assert;
* @see Async
* @see AsyncAnnotationAdvisor
* @see #setBeforeExistingAdvisors
* @see ScheduledAnnotationBeanPostProcessor
*/
@SuppressWarnings("serial")
public class AsyncAnnotationBeanPostProcessor extends AbstractAdvisingBeanPostProcessor implements BeanFactoryAware {
/**
* The default name of the {@link TaskExecutor} bean to pick up: "taskExecutor".
* <p>Note that the initial lookup happens by type; this is just the fallback
* in case of multiple executor beans found in the context.
*/
public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME = "taskExecutor";
protected final Log logger = LogFactory.getLog(getClass());
private Class<? extends Annotation> asyncAnnotationType;
private Executor executor;
@ -100,9 +116,35 @@ public class AsyncAnnotationBeanPostProcessor extends AbstractAdvisingBeanPostPr @@ -100,9 +116,35 @@ public class AsyncAnnotationBeanPostProcessor extends AbstractAdvisingBeanPostPr
this.exceptionHandler = exceptionHandler;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
Executor executorToUse = this.executor;
if (executorToUse == null) {
try {
// Search for TaskExecutor bean... not plain Executor since that would
// match with ScheduledExecutorService as well, which is unusable for
// our purposes here. TaskExecutor is more clearly designed for it.
executorToUse = beanFactory.getBean(TaskExecutor.class);
}
catch (NoUniqueBeanDefinitionException ex) {
try {
executorToUse = beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, TaskExecutor.class);
}
catch (NoSuchBeanDefinitionException ex2) {
throw new IllegalStateException("More than one TaskExecutor bean exists within the context, " +
"and none is named 'taskExecutor'. Mark one of them as primary or name it " +
"'taskExecutor' (possibly as an alias); or specify the AsyncConfigurer interface " +
"and implement getAsyncExecutor() accordingly.", ex);
}
}
catch (NoSuchBeanDefinitionException ex) {
logger.debug("Could not find default TaskExecutor bean", ex);
// Giving up -> falling back to default executor within the advisor...
}
}
AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(executorToUse, this.exceptionHandler);
if (this.asyncAnnotationType != null) {
advisor.setAsyncAnnotationType(this.asyncAnnotationType);
}

3
spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java

@ -82,13 +82,14 @@ import org.springframework.util.StringValueResolver; @@ -82,13 +82,14 @@ import org.springframework.util.StringValueResolver;
* @see SchedulingConfigurer
* @see org.springframework.scheduling.TaskScheduler
* @see org.springframework.scheduling.config.ScheduledTaskRegistrar
* @see AsyncAnnotationBeanPostProcessor
*/
public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered,
EmbeddedValueResolverAware, BeanFactoryAware, ApplicationContextAware,
SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {
/**
* The default name of the TaskScheduler bean to pick up: "taskScheduler".
* The default name of the {@link TaskScheduler} bean to pick up: "taskScheduler".
* <p>Note that the initial lookup happens by type; this is just the fallback
* in case of multiple scheduler beans found in the context.
*/

57
spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessorTests.java

@ -87,6 +87,60 @@ public class AsyncAnnotationBeanPostProcessorTests { @@ -87,6 +87,60 @@ public class AsyncAnnotationBeanPostProcessorTests {
context.close();
}
@Test
public void taskExecutorByBeanType() {
StaticApplicationContext context = new StaticApplicationContext();
BeanDefinition processorDefinition = new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
BeanDefinition executorDefinition = new RootBeanDefinition(ThreadPoolTaskExecutor.class);
executorDefinition.getPropertyValues().add("threadNamePrefix", "testExecutor");
context.registerBeanDefinition("myExecutor", executorDefinition);
BeanDefinition targetDefinition =
new RootBeanDefinition(AsyncAnnotationBeanPostProcessorTests.TestBean.class);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ITestBean testBean = context.getBean("target", ITestBean.class);
testBean.test();
testBean.await(3000);
Thread asyncThread = testBean.getThread();
assertTrue(asyncThread.getName().startsWith("testExecutor"));
context.close();
}
@Test
public void taskExecutorByBeanName() {
StaticApplicationContext context = new StaticApplicationContext();
BeanDefinition processorDefinition = new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class);
context.registerBeanDefinition("postProcessor", processorDefinition);
BeanDefinition executorDefinition = new RootBeanDefinition(ThreadPoolTaskExecutor.class);
executorDefinition.getPropertyValues().add("threadNamePrefix", "testExecutor");
context.registerBeanDefinition("myExecutor", executorDefinition);
BeanDefinition executorDefinition2 = new RootBeanDefinition(ThreadPoolTaskExecutor.class);
executorDefinition2.getPropertyValues().add("threadNamePrefix", "testExecutor2");
context.registerBeanDefinition("taskExecutor", executorDefinition2);
BeanDefinition targetDefinition =
new RootBeanDefinition(AsyncAnnotationBeanPostProcessorTests.TestBean.class);
context.registerBeanDefinition("target", targetDefinition);
context.refresh();
ITestBean testBean = context.getBean("target", ITestBean.class);
testBean.test();
testBean.await(3000);
Thread asyncThread = testBean.getThread();
assertTrue(asyncThread.getName().startsWith("testExecutor2"));
context.close();
}
@Test
public void configuredThroughNamespace() {
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
@ -264,6 +318,7 @@ public class AsyncAnnotationBeanPostProcessorTests { @@ -264,6 +318,7 @@ public class AsyncAnnotationBeanPostProcessorTests {
}
}
private static class DirectExecutor implements Executor {
@Override
@ -272,6 +327,7 @@ public class AsyncAnnotationBeanPostProcessorTests { @@ -272,6 +327,7 @@ public class AsyncAnnotationBeanPostProcessorTests {
}
}
@Configuration
@EnableAsync
static class ConfigWithExceptionHandler extends AsyncConfigurerSupport {
@ -292,5 +348,4 @@ public class AsyncAnnotationBeanPostProcessorTests { @@ -292,5 +348,4 @@ public class AsyncAnnotationBeanPostProcessorTests {
}
}
}

Loading…
Cancel
Save