/* * Copyright 2002-2010 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.springframework.aop.framework.Advised; import org.springframework.aop.framework.AopInfrastructureBean; import org.springframework.aop.framework.ProxyConfig; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.Ordered; import org.springframework.core.task.TaskExecutor; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** * 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</code> annotation. * * @author Mark Fisher * @author Juergen Hoeller * @since 3.0 * @see Async * @see AsyncAnnotationAdvisor */ public class AsyncAnnotationBeanPostProcessor extends ProxyConfig implements BeanPostProcessor, BeanClassLoaderAware, InitializingBean, Ordered { private Class<? extends Annotation> asyncAnnotationType; private Executor executor; private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private AsyncAnnotationAdvisor asyncAnnotationAdvisor; /** * 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</code> 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. */ public void setExecutor(Executor executor) { this.executor = executor; } public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } public void afterPropertiesSet() { this.asyncAnnotationAdvisor = (this.executor != null ? new AsyncAnnotationAdvisor(this.executor) : new AsyncAnnotationAdvisor()); if (this.asyncAnnotationType != null) { this.asyncAnnotationAdvisor.setAsyncAnnotationType(this.asyncAnnotationType); } } public int getOrder() { // This should run after all other post-processors, so that it can just add // an advisor to existing proxies rather than double-proxy. return LOWEST_PRECEDENCE; } public Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof AopInfrastructureBean) { // Ignore AOP infrastructure such as scoped proxies. return bean; } Class<?> targetClass = AopUtils.getTargetClass(bean); if (AopUtils.canApply(this.asyncAnnotationAdvisor, targetClass)) { if (bean instanceof Advised) { ((Advised) bean).addAdvisor(0, this.asyncAnnotationAdvisor); return bean; } else { ProxyFactory proxyFactory = new ProxyFactory(bean); // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. proxyFactory.copyFrom(this); proxyFactory.addAdvisor(this.asyncAnnotationAdvisor); return proxyFactory.getProxy(this.beanClassLoader); } } else { // No async proxy needed. return bean; } } }