[AOP] 4. Spring AOP中提供的种种Aspects - 异步执行

本文详细探讨了Spring AOP中的AsyncExecutionInterceptor,解释了它如何使用AsyncTaskExecutor进行异步方法执行,并与@Async注解配合工作。文章分析了Executor、TaskExecutor和AsyncTaskExecutor的层次结构,指出默认的异步Executor是SimpleAsyncTaskExecutor,并讨论了如何自定义Executor以适应不同的并发需求。
摘要由CSDN通过智能技术生成

上一篇文章介绍了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.

它交待了两件事情:

  1. 异步执行是通过AsyncTaskExecutor来执行的
  2. 通常和@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的层次结构

关于它的父类:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值