/* * Copyright 2002-2016 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.beans.factory.BeanFactory; import org.springframework.core.task.TaskExecutor; import org.springframework.util.Assert; /** * Bean post-processor that automatically applies asynchronous invocation * behavior to any bean that carries the {@link Async} annotation at class or * method-level by adding a corresponding {@link AsyncAnnotationAdvisor} to the * exposed proxy (either an existing AOP proxy or a newly generated proxy that * implements all of the target's interfaces). * * <p>The {@link TaskExecutor} responsible for the asynchronous execution may * be provided as well as the annotation type that indicates a method should be * invoked asynchronously. If no annotation type is specified, this post- * processor will detect both Spring's {@link Async @Async} annotation as well * as the EJB 3.1 {@code javax.ejb.Asynchronous} annotation. * * <p>For methods having a {@code void} return type, any exception thrown * during the asynchronous method invocation cannot be accessed by the * caller. An {@link AsyncUncaughtExceptionHandler} can be specified to handle * these cases. * * <p>Note: The underlying async advisor applies before existing advisors by default, * in order to switch to async execution as early as possible in the invocation chain. * * @author Mark Fisher * @author Juergen Hoeller * @author Stephane Nicoll * @since 3.0 * @see Async * @see AsyncAnnotationAdvisor * @see #setBeforeExistingAdvisors * @see ScheduledAnnotationBeanPostProcessor */ @SuppressWarnings("serial") public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor { /** * 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. * @since 4.2 * @see AnnotationAsyncExecutionInterceptor#DEFAULT_TASK_EXECUTOR_BEAN_NAME */ public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME = AnnotationAsyncExecutionInterceptor.DEFAULT_TASK_EXECUTOR_BEAN_NAME; protected final Log logger = LogFactory.getLog(getClass()); private Class<? extends Annotation> asyncAnnotationType; private Executor executor; private AsyncUncaughtExceptionHandler exceptionHandler; public AsyncAnnotationBeanPostProcessor() { setBeforeExistingAdvisors(true); } /** * Set the 'async' annotation type to be detected at either class or method * level. By default, both the {@link Async} annotation and the EJB 3.1 * {@code javax.ejb.Asynchronous} annotation will be detected. * <p>This setter property exists so that developers can provide their own * (non-Spring-specific) annotation type to indicate that a method (or all * methods of a given class) should be invoked asynchronously. * @param asyncAnnotationType the desired annotation type */ public void setAsyncAnnotationType(Class<? extends Annotation> asyncAnnotationType) { Assert.notNull(asyncAnnotationType, "'asyncAnnotationType' must not be null"); this.asyncAnnotationType = asyncAnnotationType; } /** * Set the {@link Executor} to use when invoking methods asynchronously. * <p>If not specified, default executor resolution will apply: searching for a * unique {@link TaskExecutor} bean in the context, or for an {@link Executor} * bean named "taskExecutor" otherwise. If neither of the two is resolvable, * a local default executor will be created within the interceptor. * @see AsyncAnnotationAdvisor#AsyncAnnotationAdvisor(Executor, AsyncUncaughtExceptionHandler) * @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory) * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME */ public void setExecutor(Executor executor) { this.executor = executor; } /** * Set the {@link AsyncUncaughtExceptionHandler} to use to handle uncaught * exceptions thrown by asynchronous method executions. * @since 4.1 */ public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; } @Override public void setBeanFactory(BeanFactory beanFactory) { super.setBeanFactory(beanFactory); AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler); if (this.asyncAnnotationType != null) { advisor.setAsyncAnnotationType(this.asyncAnnotationType); } advisor.setBeanFactory(beanFactory); this.advisor = advisor; } }