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}