001/* 002 * Copyright 2002-2017 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.reflect.Method; 020import java.util.concurrent.Executor; 021 022import org.springframework.aop.interceptor.AsyncExecutionInterceptor; 023import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; 024import org.springframework.core.annotation.AnnotatedElementUtils; 025import org.springframework.lang.Nullable; 026 027/** 028 * Specialization of {@link AsyncExecutionInterceptor} that delegates method execution to 029 * an {@code Executor} based on the {@link Async} annotation. Specifically designed to 030 * support use of {@link Async#value()} executor qualification mechanism introduced in 031 * Spring 3.1.2. Supports detecting qualifier metadata via {@code @Async} at the method or 032 * declaring class level. See {@link #getExecutorQualifier(Method)} for details. 033 * 034 * @author Chris Beams 035 * @author Stephane Nicoll 036 * @since 3.1.2 037 * @see org.springframework.scheduling.annotation.Async 038 * @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor 039 */ 040public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionInterceptor { 041 042 /** 043 * Create a new {@code AnnotationAsyncExecutionInterceptor} with the given executor 044 * and a simple {@link AsyncUncaughtExceptionHandler}. 045 * @param defaultExecutor the executor to be used by default if no more specific 046 * executor has been qualified at the method level using {@link Async#value()}; 047 * as of 4.2.6, a local executor for this interceptor will be built otherwise 048 */ 049 public AnnotationAsyncExecutionInterceptor(@Nullable Executor defaultExecutor) { 050 super(defaultExecutor); 051 } 052 053 /** 054 * Create a new {@code AnnotationAsyncExecutionInterceptor} with the given executor. 055 * @param defaultExecutor the executor to be used by default if no more specific 056 * executor has been qualified at the method level using {@link Async#value()}; 057 * as of 4.2.6, a local executor for this interceptor will be built otherwise 058 * @param exceptionHandler the {@link AsyncUncaughtExceptionHandler} to use to 059 * handle exceptions thrown by asynchronous method executions with {@code void} 060 * return type 061 */ 062 public AnnotationAsyncExecutionInterceptor(@Nullable Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) { 063 super(defaultExecutor, exceptionHandler); 064 } 065 066 067 /** 068 * Return the qualifier or bean name of the executor to be used when executing the 069 * given method, specified via {@link Async#value} at the method or declaring 070 * class level. If {@code @Async} is specified at both the method and class level, the 071 * method's {@code #value} takes precedence (even if empty string, indicating that 072 * the default executor should be used preferentially). 073 * @param method the method to inspect for executor qualifier metadata 074 * @return the qualifier if specified, otherwise empty string indicating that the 075 * {@linkplain #setExecutor(Executor) default executor} should be used 076 * @see #determineAsyncExecutor(Method) 077 */ 078 @Override 079 @Nullable 080 protected String getExecutorQualifier(Method method) { 081 // Maintainer's note: changes made here should also be made in 082 // AnnotationAsyncExecutionAspect#getExecutorQualifier 083 Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class); 084 if (async == null) { 085 async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class); 086 } 087 return (async != null ? async.value() : null); 088 } 089 090}