上一篇文章介绍了Spring AOP中提供的种种与Tracing相关的Aspects,还剩两个Aspects没有讨论:
- AsyncExecutionInterceptor
- ConcurrencyThrottleInterceptor
本文继续探讨和异步与并发相关一个Aspect,也是使用的比较普遍的一个:
- AsyncExecutionInterceptor
在下篇文章中会继续讨论ConcurrencyThrottleInterceptor。
AsyncExecutionInterceptor
首先来看看这个类的和其相关类的一个层次关系:
从这个类的文档来看:
AOP Alliance that processes method invocations asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}. Typically used with the {@link org.springframework.scheduling.annotation.Async} annotation.
它交待了两件事情:
- 异步执行是通过AsyncTaskExecutor来执行的
- 通常和@Async这个注解一起使用
因此,就先来看看AsyncTaskExecutor和它的父接口们是如何定义的:
AsyncTaskExecutor执行者的抽象层次
Executor
层次结构上的最顶层是位于并发包内的Executor接口。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
就定义了一个execute方法,接受一个Runnable作为待执行任务的定义。它的目的在于将任务和执行任务的基础设施(新创建的线程/线程池中的线程/当前调用线程)解耦。即任务并不清楚它自身将会被谁给执行。
TaskExecutor
位于org.springframework.core.task
包中的接口。它直接覆盖了Executor接口中对于execute方法的定义。并且将原来的参数名称从command改成了task。其实这也更清晰地表达了Runnable接口的实质意义,它代表的是一些可执行的指令,这些可执行的指令构成了一个任务。
public interface TaskExecutor extends Executor {
/**
* Execute the given {@code task}.
* <p>The call might return immediately if the implementation uses
* an asynchronous execution strategy, or might block in the case
* of synchronous execution.
* @param task the {@code Runnable} to execute (never {@code null})
* @throws TaskRejectedException if the given task was not accepted
*/
@Override
void execute(Runnable task);
}
这里同时提到了这个方法可能会立即返回(当异步执行的时候),也可能会被阻塞(当同步执行的时候,即有可能使用的是当前调用线程来执行该任务)。
AsyncTaskExecutor
public interface AsyncTaskExecutor extends TaskExecutor {
/** Constant that indicates immediate execution */
long TIMEOUT_IMMEDIATE = 0;
/** Constant that indicates no time limit */
long TIMEOUT_INDEFINITE = Long.MAX_VALUE;
/**
* Execute the given {@code task}.
* @throws TaskRejectedException if the given task was not accepted
*/
void execute(Runnable task, long startTimeout);
/**
* Submit a Runnable task for execution, receiving a Future representing that task.
* @since 3.0
*/
Future<?> submit(Runnable task);
/**
* Submit a Callable task for execution, receiving a Future
* @since 3.0
*/
<T> Future<T> submit(Callable<T> task);
}
这个接口定义了三个方法。一个方法作为execute方法的重载,添加了一个startTimeout参数用于指定待执行任务的紧急程度。接口中定义的两个常量就是描述该信息的。比如使用TIMEOUT_IMMEDIATE就意味着当前任务很紧急,需要立即执行。但是这个参数也只是给底层的任务执行者一个提示(Hint),是否参考还要看具体实现。而默认不使用startTimeout参数的重载会使用TIMEOUT_INDEFINITE作为默认值,此时任务的优先级定义的是比较低的。
另外两个submit方法则是为异步任务执行添加的,在提交任务后会得到一个Future对象作为获取结果的凭证,这个Future可以理解成JavaScript中的Promise。两者本质上就是同样的概念。同时,还支持了基于Callable接口的任务,Callable和Runnable最大的区别就在于前者有返回值的概念,因此它也更贴近于Task的概念。
AsyncExecutionInterceptor的层次结构
关于它的父类: