@Async's qualifier works for target class annotations behind a JDK proxy as well
Also optimized AsyncExecutionAspectSupport's Executor-per-Method caching to use a ConcurrentHashMap. Issue: SPR-10274
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -39,7 +39,7 @@ public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionIntercept
|
||||
/**
|
||||
* Create a new {@code AnnotationAsyncExecutionInterceptor} with the given executor.
|
||||
* @param defaultExecutor the executor to be used by default if no more specific
|
||||
* executor has been qualified at the method level using {@link Async#value()}.
|
||||
* executor has been qualified at the method level using {@link Async#value()}
|
||||
*/
|
||||
public AnnotationAsyncExecutionInterceptor(Executor defaultExecutor) {
|
||||
super(defaultExecutor);
|
||||
@@ -64,7 +64,7 @@ public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionIntercept
|
||||
if (async == null) {
|
||||
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
|
||||
}
|
||||
return async == null ? null : async.value();
|
||||
return (async != null ? async.value() : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -28,7 +28,6 @@ import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||
import org.springframework.aop.support.ComposablePointcut;
|
||||
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
@@ -58,8 +57,6 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
|
||||
private Pointcut pointcut;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code AsyncAnnotationAdvisor} for bean-style configuration.
|
||||
@@ -84,30 +81,15 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
// If EJB 3.1 API not present, simply ignore.
|
||||
}
|
||||
this.advice = buildAdvice(executor);
|
||||
this.setTaskExecutor(executor);
|
||||
this.pointcut = buildPointcut(asyncAnnotationTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code BeanFactory} to be used when looking up executors by qualifier.
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
delegateBeanFactory(beanFactory);
|
||||
}
|
||||
|
||||
public void delegateBeanFactory(BeanFactory beanFactory) {
|
||||
if (this.advice instanceof AnnotationAsyncExecutionInterceptor) {
|
||||
((AnnotationAsyncExecutionInterceptor)this.advice).setBeanFactory(beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the task executor to use for asynchronous methods.
|
||||
* Specify the default task executor to use for asynchronous methods.
|
||||
*/
|
||||
public void setTaskExecutor(Executor executor) {
|
||||
this.advice = buildAdvice(executor);
|
||||
delegateBeanFactory(this.beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,6 +108,15 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
|
||||
this.pointcut = buildPointcut(asyncAnnotationTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code BeanFactory} to be used when looking up executors by qualifier.
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (this.advice instanceof BeanFactoryAware) {
|
||||
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Advice getAdvice() {
|
||||
return this.advice;
|
||||
|
||||
@@ -66,6 +66,21 @@ public class AsyncExecutionTests {
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodsThroughInterface() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(SimpleAsyncMethodBean.class));
|
||||
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
|
||||
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
|
||||
context.refresh();
|
||||
SimpleInterface asyncTest = context.getBean("asyncTest", SimpleInterface.class);
|
||||
asyncTest.doNothing(5);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodsWithQualifier() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
@@ -86,6 +101,26 @@ public class AsyncExecutionTests {
|
||||
assertEquals("30", future2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMethodsWithQualifierThroughInterface() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(SimpleAsyncMethodWithQualifierBean.class));
|
||||
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
|
||||
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
|
||||
context.registerBeanDefinition("e0", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
|
||||
context.registerBeanDefinition("e1", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
|
||||
context.registerBeanDefinition("e2", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
|
||||
context.refresh();
|
||||
SimpleInterface asyncTest = context.getBean("asyncTest", SimpleInterface.class);
|
||||
asyncTest.doNothing(5);
|
||||
asyncTest.doSomething(10);
|
||||
Future<String> future = asyncTest.returnSomething(20);
|
||||
assertEquals("20", future.get());
|
||||
Future<String> future2 = asyncTest.returnSomething2(30);
|
||||
assertEquals("30", future2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncClass() throws Exception {
|
||||
originalThreadName = Thread.currentThread().getName();
|
||||
@@ -177,6 +212,18 @@ public class AsyncExecutionTests {
|
||||
}
|
||||
|
||||
|
||||
public interface SimpleInterface {
|
||||
|
||||
void doNothing(int i);
|
||||
|
||||
void doSomething(int i);
|
||||
|
||||
Future<String> returnSomething(int i);
|
||||
|
||||
Future<String> returnSomething2(int i);
|
||||
}
|
||||
|
||||
|
||||
public static class AsyncMethodBean {
|
||||
|
||||
public void doNothing(int i) {
|
||||
@@ -196,6 +243,15 @@ public class AsyncExecutionTests {
|
||||
}
|
||||
|
||||
|
||||
public static class SimpleAsyncMethodBean extends AsyncMethodBean implements SimpleInterface {
|
||||
|
||||
@Override
|
||||
public Future<String> returnSomething2(int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Async("e0")
|
||||
public static class AsyncMethodWithQualifierBean {
|
||||
|
||||
@@ -224,6 +280,10 @@ public class AsyncExecutionTests {
|
||||
}
|
||||
|
||||
|
||||
public static class SimpleAsyncMethodWithQualifierBean extends AsyncMethodWithQualifierBean implements SimpleInterface {
|
||||
}
|
||||
|
||||
|
||||
@Async("e2")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyAsync {
|
||||
|
||||
Reference in New Issue
Block a user