当前位置:首页 > 技术分析 > 正文内容

你知道@Async 是怎么让方法异步执行的吗?

ruisui884个月前 (02-14)技术分析23

对于Spring的封装能力,大家应该是不陌生的,因此对于很多读者来讲,学会了它的使用,并不会去研究其底层的实现。例如@Async 注解,一般人可能只是注意到它是一个注解,并且在方法或者类上添加上整个注解之后,Spring会将对应的方法或者类中的所有方法都放到一个单独的线程池中去执行,通过这种方式来实现异步执行操作。但是对于@Async到底是如何运行的却不得而知,这篇文章就来跟大家一起学习其原理。

@Async

首先,需要只知道这个注解是用来标注开启异步执行操作的注解。对于这个注解本身来讲,除了依赖于Java底层的支持,还依赖了一些Spring相关的内容。通过反射的方式拦截到了标注有该注解的类,然后通过AOP来进行切面的拦截。进行切面拦击之后,就需要去实现异步方法的执行。带着这个思路我们来分析一下@Async 的原理。

如何开启异步操作呢?

在Spring中通过@EnableAsync注解来开启异步执行方法的操作。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
	Class annotation() default Annotation.class;
	boolean proxyTargetClass() default false;
	AdviceMode mode() default AdviceMode.PROXY;
	int order() default Ordered.LOWEST_PRECEDENCE;

}

从代码中可以看到在@EnableAsync 中Import导入了一个
AsyncConfigurationSelector ,这种引入也是Spring提供的引入第三方的依赖的方式。通过类名可以知道引入的是一个异步执行配置的选择器。这个默认选择器就是ProxyAsyncConfiguration

在这个类中有如下的方法,注入了
AsyncAnnotationBeanPostProcessor处理器。从名称上来看就是用来处理@Async 注解的处理器。

在这个处理器中存在一个
AnnotationAsyncExecutionInterceptor的拦截器,根据我们上面的分析可以知道,AOP的最外层是代理类,然后进行切面。通过Advisor创建切面。这些操作都是在
AsyncAnnotationBeanPostProcessor,中来完成,如下图所示

并且在AsyncAnnotationAdvisor中创建了advice和pointcut,并且在拦截器操作中就是对advice的处理。

完成这些操作之后,关于@EnableAsync注解的作用就算完成了。它主要的操作就是利用AOP技术创建好一个切面,这个切面上所有的操作都是关于@Async的操作。

具体实现原理

在上面的介绍中,我们知道了@EnableAsync 的生效是通过AOP来实现的。但是在实现了AOP操作之后,就需要将异步操作放入到一个异步的线程池中去执行。下面我们就要去看看执行操作的线程池是在哪一步进行创建的。

在前面的分析中介绍了一个
AnnotationAsyncExecutionInterceptor 拦截器类,需要创建线程池的操作就是在这个拦截器中完成的

在其父类
AsyncExecutionAspectSupport中完成了对执行线程池的创建。

并且通过getDefaultExecutor 方法来获取到Spring容器中对应的执行的线程池Bean。当然在没有进行配置的情况下,默认使用的是SimpleAsyncTaskExecutor线程池。

提交执行任务执行

基于上面的分析,我们这回到,当方法被@Async注解的时候,也就是会被
AnnotationAsyncExecutionInterceptor拦截器所拦截,并且通过代码分析我们找到了相关的拦截处理机制。在其父类AsyncExecutionInterceptor 中,对提交的任务进行验证分析处理。

其中determineAsyncExecutor 中获取到的就是执行的executor与具体方法对象绑定的关系,并且对于每个添加了@Async的方法来讲都会有一个独立的executor,然后调用doSubmit方法执行,并且根据对应的returnType对返回值进行处理。

自定义线程池

在上面的分析中,我们提到了可以通过配置的方式来自定义执行线程池。在SpringBoot中提供了一个AsyncConfigurer 接口来让开发人员自定义实现的线程池。可以通过继承AsyncConfigurerSupport类并且实现其中的方法来实现。需要注意的是,AsyncConfigurer在每个项目中只能有一个实现Bean实例。如果出现多个,则会抛出异常。

总结

上面我们介绍了关于@Async的相关执行原理,从整个的分析来看,基本上行基于Spring的一些优秀的实现项目都是离不开Spring的核心IOC和AOP操作。当然通过代码分析只是掌握其运行原理的一种途径,有兴趣的读者也可以利用Spring框架提供的一些便携操作来完成更加高级的实现。

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/1967.html

标签: aysnc
分享给朋友:

“你知道@Async 是怎么让方法异步执行的吗?” 的相关文章

细数5款国外热门Linux发行版

Linux系统已经与我们的生活息息相关,当你用Android手机浏览这篇文章时,你就已经在使用Linux系统。当然作为编程开发最热门的系统,他还有很多专注于开发使用的版本。Fedora热门入门推荐,一款优秀的程序猿专供Linux发行版,自带开发者门户,集成大量教程指南、开发集成环境、虚拟机等工具,简...

Linux发行版Debian推出12.2及11.8版本,修复多个安全问题

IT之家 10 月 9 日消息,Debian 是最古老的 GNU / Linux 发行版之一,也是许多其他基于 Linux 的操作系统的基础,包括 Ubuntu、Kali、MX 和树莓派 OS 等,近日 Debian 推出了 12.2 和 11.8 版本,主要修复了多个安全问题。▲ 图源 Debia...

「干货」通俗易懂的Deno 入门教程

作者: semlinker转发链接:https://mp.weixin.qq.com/s/2eqRTsf_z7Bcs6dziXe73Q一、Deno 简介Deno 是一个 JavaScript/TypeScript 的运行时,默认使用安全环境执行代码,有着卓越的开发体验。Deno 含有以下功能亮点:默...

迁移GIT仓库并带有历史提交记录

迁移git仓库开发在很多时候,会遇到一个问题。GIT仓库的管理,特别是仓库的迁移。我需要保留已有的历史记录,而不是重新开发,重头再来。我们可以这样做:使用--mirror模式会把本地的分支都克隆。// 先用--bare克隆裸仓库 git clone git@gitee.com:xxx/testApp...

Python 幕后:Python导入import的工作原理

更多互联网精彩资讯、工作效率提升关注【飞鱼在浪屿】(日更新)Python 最容易被误解的方面其中之一是import。Python 导入系统不仅看起来很复杂。因此,即使文档非常好,它也不能让您全面了解正在发生的事情。唯一方法是研究 Python 执行 import 语句时幕后发生的事情。注意:在这篇文...

2024年,不断突破的一年

迈凯伦F1车队不久前拿下了2024年度总冠军,距离上一次还是二十几年前。在此期间,另一领域内,一个充满革新活力的腕表品牌——RICHARD MILLE理查米尔,正不断发展,与F1运动、帆船、古董车展等领域,共享着对速度与极限的无尽向往。RICHARD MILLE的发展与F1车手们在赛道上的卓越表现交...