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}