Provides support for executor qualification on a method-by-method basis.
@@ -42,14 +47,19 @@ import org.springframework.util.StringUtils;
*
* @author Chris Beams
* @author Juergen Hoeller
+ * @author Stephane Nicoll
* @since 3.1.2
*/
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
+ protected final Log logger = LogFactory.getLog(getClass());
+
private final Map executors = new ConcurrentHashMap(16);
private Executor defaultExecutor;
+ private AsyncUncaughtExceptionHandler exceptionHandler;
+
private BeanFactory beanFactory;
@@ -58,9 +68,18 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* executor unless individual async methods indicate via qualifier that a more
* specific executor should be used.
* @param defaultExecutor the executor to use when executing asynchronous methods
+ * @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use
+ */
+ public AsyncExecutionAspectSupport(Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) {
+ this.defaultExecutor = defaultExecutor;
+ this.exceptionHandler = exceptionHandler;
+ }
+
+ /**
+ * Create a new instance with a default {@link AsyncUncaughtExceptionHandler}.
*/
public AsyncExecutionAspectSupport(Executor defaultExecutor) {
- this.defaultExecutor = defaultExecutor;
+ this(defaultExecutor, new SimpleAsyncUncaughtExceptionHandler());
}
@@ -78,6 +97,14 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
this.defaultExecutor = defaultExecutor;
}
+ /**
+ * Supply the {@link AsyncUncaughtExceptionHandler} to use to handle exceptions
+ * thrown by invoking asynchronous methods with a {@code void} return type.
+ */
+ public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) {
+ this.exceptionHandler = exceptionHandler;
+ }
+
/**
* Set the {@link BeanFactory} to be used when looking up executors by qualifier.
*/
@@ -125,4 +152,32 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
*/
protected abstract String getExecutorQualifier(Method method);
+ /**
+ * Handles a fatal error thrown while asynchronously invoking the specified
+ * {@link Method}.
+ *
If the return type of the method is a {@link java.util.concurrent.Future} object, the original
+ * exception can be propagated by just throwing it at the higher level. However,
+ * for all other cases, the exception will not be transmitted back to the client.
+ * In that later case, the current {@link AsyncUncaughtExceptionHandler} will be
+ * used to manage such exception.
+ * @param ex the exception to handle
+ * @param method the method that was invoked
+ * @param params the parameters used to invoke the method
+ */
+ protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
+ if (method.getReturnType().isAssignableFrom(Future.class)) {
+ ReflectionUtils.rethrowException(ex);
+ }
+ else {
+ // Could not transmit the exception to the caller with default executor
+ try {
+ this.exceptionHandler.handleUncaughtException(ex, method, params);
+ }
+ catch (Throwable ex2) {
+ logger.error("Exception handler for async method '" + method.toGenericString() +
+ "' threw unexpected exception itself", ex2);
+ }
+ }
+ }
+
}
diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java
index ec7582f458f..1a89a40977d 100644
--- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java
+++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java
@@ -23,8 +23,6 @@ import java.util.concurrent.Future;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.BridgeMethodResolver;
@@ -32,7 +30,6 @@ import org.springframework.core.Ordered;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.util.ClassUtils;
-import org.springframework.util.ReflectionUtils;
import org.springframework.util.concurrent.ListenableFuture;
/**
@@ -70,11 +67,6 @@ import org.springframework.util.concurrent.ListenableFuture;
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
implements MethodInterceptor, Ordered {
- private final Log logger = LogFactory.getLog(getClass());
-
- private AsyncUncaughtExceptionHandler exceptionHandler;
-
-
/**
* Create a new {@code AsyncExecutionInterceptor}.
* @param defaultExecutor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
@@ -82,27 +74,16 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
* @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use
*/
public AsyncExecutionInterceptor(Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) {
- super(defaultExecutor);
- this.exceptionHandler = exceptionHandler;
+ super(defaultExecutor, exceptionHandler);
}
/**
* Create a new instance with a default {@link AsyncUncaughtExceptionHandler}.
*/
public AsyncExecutionInterceptor(Executor defaultExecutor) {
- this(defaultExecutor, new SimpleAsyncUncaughtExceptionHandler());
+ super(defaultExecutor);
}
-
- /**
- * Supply the {@link AsyncUncaughtExceptionHandler} to use to handle exceptions
- * thrown by invoking asynchronous methods with a {@code void} return type.
- */
- public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) {
- this.exceptionHandler = exceptionHandler;
- }
-
-
/**
* Intercept the given method invocation, submit the actual calling of the method to
* the correct task executor and return immediately to the caller.
@@ -151,34 +132,6 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
}
}
- /**
- * Handles a fatal error thrown while asynchronously invoking the specified
- * {@link Method}.
- *
If the return type of the method is a {@link Future} object, the original
- * exception can be propagated by just throwing it at the higher level. However,
- * for all other cases, the exception will not be transmitted back to the client.
- * In that later case, the current {@link AsyncUncaughtExceptionHandler} will be
- * used to manage such exception.
- * @param ex the exception to handle
- * @param method the method that was invoked
- * @param params the parameters used to invoke the method
- */
- protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
- if (method.getReturnType().isAssignableFrom(Future.class)) {
- ReflectionUtils.rethrowException(ex);
- }
- else {
- // Could not transmit the exception to the caller with default executor
- try {
- this.exceptionHandler.handleUncaughtException(ex, method, params);
- }
- catch (Throwable ex2) {
- logger.error("Exception handler for async method '" + method.toGenericString() +
- "' threw unexpected exception itself", ex2);
- }
- }
- }
-
/**
* This implementation is a no-op for compatibility in Spring 3.1.2.
* Subclasses may override to provide support for extracting qualifier information,
diff --git a/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj b/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj
index 660b35c1361..2f2455367e1 100644
--- a/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj
+++ b/spring-aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2014 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.
@@ -35,6 +35,7 @@ import org.springframework.core.task.AsyncTaskExecutor;
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @author Chris Beams
+ * @author Stephane Nicoll
* @since 3.0.5
*/
public abstract aspect AbstractAsyncExecutionAspect extends AsyncExecutionAspectSupport {
@@ -42,7 +43,7 @@ public abstract aspect AbstractAsyncExecutionAspect extends AsyncExecutionAspect
/**
* Create an {@code AnnotationAsyncExecutionAspect} with a {@code null} default
* executor, which should instead be set via {@code #aspectOf} and
- * {@link #setExecutor(Executor)}.
+ * {@link #setExecutor(Executor)}. The same applies for {@link #setExceptionHandler}
*/
public AbstractAsyncExecutionAspect() {
super(null);
@@ -56,16 +57,21 @@ public abstract aspect AbstractAsyncExecutionAspect extends AsyncExecutionAspect
* otherwise.
*/
Object around() : asyncMethod() {
- MethodSignature methodSignature = (MethodSignature) thisJoinPointStaticPart.getSignature();
+ final MethodSignature methodSignature = (MethodSignature) thisJoinPointStaticPart.getSignature();
AsyncTaskExecutor executor = determineAsyncExecutor(methodSignature.getMethod());
if (executor == null) {
return proceed();
}
Callable