001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.scheduling.annotation; 018 019import java.lang.annotation.Annotation; 020import java.util.concurrent.Executor; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor; 026import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; 027import org.springframework.beans.factory.BeanFactory; 028import org.springframework.core.task.TaskExecutor; 029import org.springframework.util.Assert; 030 031/** 032 * Bean post-processor that automatically applies asynchronous invocation 033 * behavior to any bean that carries the {@link Async} annotation at class or 034 * method-level by adding a corresponding {@link AsyncAnnotationAdvisor} to the 035 * exposed proxy (either an existing AOP proxy or a newly generated proxy that 036 * implements all of the target's interfaces). 037 * 038 * <p>The {@link TaskExecutor} responsible for the asynchronous execution may 039 * be provided as well as the annotation type that indicates a method should be 040 * invoked asynchronously. If no annotation type is specified, this post- 041 * processor will detect both Spring's {@link Async @Async} annotation as well 042 * as the EJB 3.1 {@code javax.ejb.Asynchronous} annotation. 043 * 044 * <p>For methods having a {@code void} return type, any exception thrown 045 * during the asynchronous method invocation cannot be accessed by the 046 * caller. An {@link AsyncUncaughtExceptionHandler} can be specified to handle 047 * these cases. 048 * 049 * <p>Note: The underlying async advisor applies before existing advisors by default, 050 * in order to switch to async execution as early as possible in the invocation chain. 051 * 052 * @author Mark Fisher 053 * @author Juergen Hoeller 054 * @author Stephane Nicoll 055 * @since 3.0 056 * @see Async 057 * @see AsyncAnnotationAdvisor 058 * @see #setBeforeExistingAdvisors 059 * @see ScheduledAnnotationBeanPostProcessor 060 */ 061@SuppressWarnings("serial") 062public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor { 063 064 /** 065 * The default name of the {@link TaskExecutor} bean to pick up: "taskExecutor". 066 * <p>Note that the initial lookup happens by type; this is just the fallback 067 * in case of multiple executor beans found in the context. 068 * @since 4.2 069 * @see AnnotationAsyncExecutionInterceptor#DEFAULT_TASK_EXECUTOR_BEAN_NAME 070 */ 071 public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME = 072 AnnotationAsyncExecutionInterceptor.DEFAULT_TASK_EXECUTOR_BEAN_NAME; 073 074 075 protected final Log logger = LogFactory.getLog(getClass()); 076 077 private Class<? extends Annotation> asyncAnnotationType; 078 079 private Executor executor; 080 081 private AsyncUncaughtExceptionHandler exceptionHandler; 082 083 084 public AsyncAnnotationBeanPostProcessor() { 085 setBeforeExistingAdvisors(true); 086 } 087 088 089 /** 090 * Set the 'async' annotation type to be detected at either class or method 091 * level. By default, both the {@link Async} annotation and the EJB 3.1 092 * {@code javax.ejb.Asynchronous} annotation will be detected. 093 * <p>This setter property exists so that developers can provide their own 094 * (non-Spring-specific) annotation type to indicate that a method (or all 095 * methods of a given class) should be invoked asynchronously. 096 * @param asyncAnnotationType the desired annotation type 097 */ 098 public void setAsyncAnnotationType(Class<? extends Annotation> asyncAnnotationType) { 099 Assert.notNull(asyncAnnotationType, "'asyncAnnotationType' must not be null"); 100 this.asyncAnnotationType = asyncAnnotationType; 101 } 102 103 /** 104 * Set the {@link Executor} to use when invoking methods asynchronously. 105 * <p>If not specified, default executor resolution will apply: searching for a 106 * unique {@link TaskExecutor} bean in the context, or for an {@link Executor} 107 * bean named "taskExecutor" otherwise. If neither of the two is resolvable, 108 * a local default executor will be created within the interceptor. 109 * @see AsyncAnnotationAdvisor#AsyncAnnotationAdvisor(Executor, AsyncUncaughtExceptionHandler) 110 * @see AnnotationAsyncExecutionInterceptor#getDefaultExecutor(BeanFactory) 111 * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME 112 */ 113 public void setExecutor(Executor executor) { 114 this.executor = executor; 115 } 116 117 /** 118 * Set the {@link AsyncUncaughtExceptionHandler} to use to handle uncaught 119 * exceptions thrown by asynchronous method executions. 120 * @since 4.1 121 */ 122 public void setExceptionHandler(AsyncUncaughtExceptionHandler exceptionHandler) { 123 this.exceptionHandler = exceptionHandler; 124 } 125 126 127 @Override 128 public void setBeanFactory(BeanFactory beanFactory) { 129 super.setBeanFactory(beanFactory); 130 131 AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler); 132 if (this.asyncAnnotationType != null) { 133 advisor.setAsyncAnnotationType(this.asyncAnnotationType); 134 } 135 advisor.setBeanFactory(beanFactory); 136 this.advisor = advisor; 137 } 138 139}