AsyncExecutionAspectSupport.java 5.0 KB
Newer Older
1
/*
2
 * Copyright 2002-2013 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.interceptor;

import java.lang.reflect.Method;
import java.util.Map;
21
import java.util.concurrent.ConcurrentHashMap;
22 23 24 25 26
import java.util.concurrent.Executor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
27
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
28 29 30 31 32 33 34 35
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * Base class for asynchronous method execution aspects, such as
 * {@link org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor}
C
Chris Beams 已提交
36
 * or {@code org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect}.
37 38 39 40 41 42 43
 *
 * <p>Provides support for <i>executor qualification</i> on a method-by-method basis.
 * {@code AsyncExecutionAspectSupport} objects must be constructed with a default {@code
 * Executor}, but each individual method may further qualify a specific {@code Executor}
 * bean to be used when executing it, e.g. through an annotation attribute.
 *
 * @author Chris Beams
44
 * @since 3.1.2
45 46 47
 */
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {

48
	private final Map<Method, AsyncTaskExecutor> executors = new ConcurrentHashMap<Method, AsyncTaskExecutor>(16);
49 50 51 52 53 54 55 56 57 58 59 60 61

	private Executor defaultExecutor;

	private BeanFactory beanFactory;


	/**
	 * Create a new {@link AsyncExecutionAspectSupport}, using the provided default
	 * executor unless individual async methods indicate via qualifier that a more
	 * specific executor should be used.
	 * @param defaultExecutor the executor to use when executing asynchronous methods
	 */
	public AsyncExecutionAspectSupport(Executor defaultExecutor) {
62
		this.defaultExecutor = defaultExecutor;
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	}


	/**
	 * Supply the executor to be used when executing async methods.
	 * @param defaultExecutor the {@code Executor} (typically a Spring {@code
	 * AsyncTaskExecutor} or {@link java.util.concurrent.ExecutorService}) to delegate to
	 * unless a more specific executor has been requested via a qualifier on the async
	 * method, in which case the executor will be looked up at invocation time against the
	 * enclosing bean factory.
	 * @see #getExecutorQualifier
	 * @see #setBeanFactory(BeanFactory)
	 */
	public void setExecutor(Executor defaultExecutor) {
		this.defaultExecutor = defaultExecutor;
	}

	/**
	 * Set the {@link BeanFactory} to be used when looking up executors by qualifier.
	 */
83
	@Override
84 85 86 87 88 89 90
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}


	/**
	 * Determine the specific executor to use when executing the given method.
C
Chris Beams 已提交
91
	 * @return the executor to use (never {@code null})
92 93
	 */
	protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
94 95 96
		AsyncTaskExecutor executor = this.executors.get(method);
		if (executor == null) {
			Executor executorToUse = this.defaultExecutor;
97 98
			String qualifier = getExecutorQualifier(method);
			if (StringUtils.hasLength(qualifier)) {
99 100 101
				Assert.notNull(this.beanFactory, "BeanFactory must be set on " + getClass().getSimpleName() +
						" to access qualified executor '" + qualifier + "'");
				executorToUse = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
102
						this.beanFactory, Executor.class, qualifier);
103
			}
104 105 106
			else if (executorToUse == null) {
				throw new IllegalStateException("No executor qualifier specified and no default executor set on " +
						getClass().getSimpleName() + " either");
107
			}
108 109 110
			executor = (executorToUse instanceof AsyncTaskExecutor ?
					(AsyncTaskExecutor) executorToUse : new TaskExecutorAdapter(executorToUse));
			this.executors.put(method, executor);
111
		}
112
		return executor;
113 114
	}

115 116 117 118 119 120 121 122 123 124 125 126
	/**
	 * Return the qualifier or bean name of the executor to be used when executing the
	 * given async method, typically specified in the form of an annotation attribute.
	 * Returning an empty string or {@code null} indicates that no specific executor has
	 * been specified and that the {@linkplain #setExecutor(Executor) default executor}
	 * should be used.
	 * @param method the method to inspect for executor qualifier metadata
	 * @return the qualifier if specified, otherwise empty string or {@code null}
	 * @see #determineAsyncExecutor(Method)
	 */
	protected abstract String getExecutorQualifier(Method method);

127
}