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