SPR-7369: @Async support in spring-aspects with AspectJ
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package org.springframework.scheduling;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
|
||||
/**
|
||||
* Abstract aspect that routes selected methods asynchronously.
|
||||
* <p>
|
||||
* This aspect, by default, uses {@link SimpleAsyncTaskExecutor} to route method
|
||||
* execution. However, you may inject it with any implementation of
|
||||
* {@link Executor} to override the default.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public abstract aspect AbstractAsynchronousExecutionAspect {
|
||||
private AsyncTaskExecutor asyncExecutor;
|
||||
|
||||
public AbstractAsynchronousExecutionAspect() {
|
||||
// Set default executor, which may be replaced by calling setExecutor(Executor)
|
||||
setExecutor(new SimpleAsyncTaskExecutor());
|
||||
}
|
||||
|
||||
public abstract pointcut asyncMethod();
|
||||
|
||||
Object around() : asyncMethod() {
|
||||
Callable<Object> callable = new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
Object result = proceed();
|
||||
if (result instanceof Future) {
|
||||
return ((Future<?>) result).get();
|
||||
}
|
||||
return null;
|
||||
}};
|
||||
|
||||
Future<?> result = asyncExecutor.submit(callable);
|
||||
|
||||
if (Future.class.isAssignableFrom(((MethodSignature)thisJoinPointStaticPart.getSignature()).getReturnType())) {
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setExecutor(Executor executor) {
|
||||
if (executor instanceof AsyncTaskExecutor) {
|
||||
this.asyncExecutor = (AsyncTaskExecutor) executor;
|
||||
} else {
|
||||
this.asyncExecutor = new TaskExecutorAdapter(asyncExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.springframework.scheduling;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* Aspect to route methods based on the {@link Async} annotation.
|
||||
* <p>
|
||||
* This aspect routes methods marked with the {@link Async} annotation
|
||||
* as well as methods in classes marked with the same. Any method expected
|
||||
* to be routed asynchronously must return either void, {@link Future},
|
||||
* or a subtype of {@link Future}. This aspect, therefore, will produce
|
||||
* a compile-time error for methods that violate this constraint on the return type.
|
||||
* If, however, a class marked with <code>@Async</code> contains a method that
|
||||
* violates this constraint, it produces only a warning.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
public aspect AnnotationDrivenAsynchronousExecutionAspect extends AbstractAsynchronousExecutionAspect {
|
||||
private pointcut asyncMarkedMethod()
|
||||
: execution(@Async (void || Future+) *(..));
|
||||
private pointcut asyncTypeMarkedMethod()
|
||||
: execution((void || Future+) (@Async *).*(..));
|
||||
|
||||
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
|
||||
|
||||
declare error:
|
||||
execution(@Async !(void||Future) *(..)):
|
||||
"Only method that return void or Future may have @Async annotation";
|
||||
|
||||
declare warning:
|
||||
execution(!(void||Future) (@Async *).*(..)):
|
||||
"Method in class marked with @Async that do not return void or Future will be routed synchronously";
|
||||
}
|
||||
Reference in New Issue
Block a user