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.aop.interceptor; 018 019import java.lang.reflect.Method; 020import java.util.concurrent.Callable; 021import java.util.concurrent.ExecutionException; 022import java.util.concurrent.Executor; 023import java.util.concurrent.Future; 024 025import org.aopalliance.intercept.MethodInterceptor; 026import org.aopalliance.intercept.MethodInvocation; 027 028import org.springframework.aop.support.AopUtils; 029import org.springframework.beans.factory.BeanFactory; 030import org.springframework.core.BridgeMethodResolver; 031import org.springframework.core.Ordered; 032import org.springframework.core.task.AsyncTaskExecutor; 033import org.springframework.core.task.SimpleAsyncTaskExecutor; 034import org.springframework.util.ClassUtils; 035 036/** 037 * AOP Alliance {@code MethodInterceptor} that processes method invocations 038 * asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}. 039 * Typically used with the {@link org.springframework.scheduling.annotation.Async} annotation. 040 * 041 * <p>In terms of target method signatures, any parameter types are supported. 042 * However, the return type is constrained to either {@code void} or 043 * {@code java.util.concurrent.Future}. In the latter case, the Future handle 044 * returned from the proxy will be an actual asynchronous Future that can be used 045 * to track the result of the asynchronous method execution. However, since the 046 * target method needs to implement the same signature, it will have to return 047 * a temporary Future handle that just passes the return value through 048 * (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult} 049 * or EJB 3.1's {@code javax.ejb.AsyncResult}). 050 * 051 * <p>When the return type is {@code java.util.concurrent.Future}, any exception thrown 052 * during the execution can be accessed and managed by the caller. With {@code void} 053 * return type however, such exceptions cannot be transmitted back. In that case an 054 * {@link AsyncUncaughtExceptionHandler} can be registered to process such exceptions. 055 * 056 * <p>As of Spring 3.1.2 the {@code AnnotationAsyncExecutionInterceptor} subclass is 057 * preferred for use due to its support for executor qualification in conjunction with 058 * Spring's {@code @Async} annotation. 059 * 060 * @author Juergen Hoeller 061 * @author Chris Beams 062 * @author Stephane Nicoll 063 * @since 3.0 064 * @see org.springframework.scheduling.annotation.Async 065 * @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor 066 * @see org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor 067 */ 068public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered { 069 070 /** 071 * Create a new instance with a default {@link AsyncUncaughtExceptionHandler}. 072 * @param defaultExecutor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor} 073 * or {@link java.util.concurrent.ExecutorService}) to delegate to; 074 * as of 4.2.6, a local executor for this interceptor will be built otherwise 075 */ 076 public AsyncExecutionInterceptor(Executor defaultExecutor) { 077 super(defaultExecutor); 078 } 079 080 /** 081 * Create a new {@code AsyncExecutionInterceptor}. 082 * @param defaultExecutor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor} 083 * or {@link java.util.concurrent.ExecutorService}) to delegate to; 084 * as of 4.2.6, a local executor for this interceptor will be built otherwise 085 * @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use 086 */ 087 public AsyncExecutionInterceptor(Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) { 088 super(defaultExecutor, exceptionHandler); 089 } 090 091 092 /** 093 * Intercept the given method invocation, submit the actual calling of the method to 094 * the correct task executor and return immediately to the caller. 095 * @param invocation the method to intercept and make asynchronous 096 * @return {@link Future} if the original method returns {@code Future}; {@code null} 097 * otherwise. 098 */ 099 @Override 100 public Object invoke(final MethodInvocation invocation) throws Throwable { 101 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); 102 Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass); 103 final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); 104 105 AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod); 106 if (executor == null) { 107 throw new IllegalStateException( 108 "No executor specified and no default executor set on AsyncExecutionInterceptor either"); 109 } 110 111 Callable<Object> task = new Callable<Object>() { 112 @Override 113 public Object call() throws Exception { 114 try { 115 Object result = invocation.proceed(); 116 if (result instanceof Future) { 117 return ((Future<?>) result).get(); 118 } 119 } 120 catch (ExecutionException ex) { 121 handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments()); 122 } 123 catch (Throwable ex) { 124 handleError(ex, userDeclaredMethod, invocation.getArguments()); 125 } 126 return null; 127 } 128 }; 129 130 return doSubmit(task, executor, invocation.getMethod().getReturnType()); 131 } 132 133 /** 134 * This implementation is a no-op for compatibility in Spring 3.1.2. 135 * Subclasses may override to provide support for extracting qualifier information, 136 * e.g. via an annotation on the given method. 137 * @return always {@code null} 138 * @since 3.1.2 139 * @see #determineAsyncExecutor(Method) 140 */ 141 @Override 142 protected String getExecutorQualifier(Method method) { 143 return null; 144 } 145 146 /** 147 * This implementation searches for a unique {@link org.springframework.core.task.TaskExecutor} 148 * bean in the context, or for an {@link Executor} bean named "taskExecutor" otherwise. 149 * If neither of the two is resolvable (e.g. if no {@code BeanFactory} was configured at all), 150 * this implementation falls back to a newly created {@link SimpleAsyncTaskExecutor} instance 151 * for local use if no default could be found. 152 * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME 153 */ 154 @Override 155 protected Executor getDefaultExecutor(BeanFactory beanFactory) { 156 Executor defaultExecutor = super.getDefaultExecutor(beanFactory); 157 return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor()); 158 } 159 160 @Override 161 public int getOrder() { 162 return Ordered.HIGHEST_PRECEDENCE; 163 } 164 165}