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

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

ruisui883个月前 (02-14)技术分析17

对于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 是怎么让方法异步执行的吗?” 的相关文章

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

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

如何在GitLab上回退指定版本的代码?GitLab回退指定版本问题分析

在Git中,回退到指定版本并不是删除或撤销之前的提交,而是创建一个新的提交,该提交包含指定版本的内容。这意味着您需要将当前代码更改与指定版本之间的差异进行比较,并将其合并到一个新的提交中。如果您没有更新本地代码,并且您希望将 GitLab 仓库回退到指定版本,您可以使用以下命令:git fetchg...

继Yuzu后,任天堂要求移除多个Switch模拟器项目

IT之家 7 月 11 日消息,任天堂美国分公司 (Nintendo of America) 已要求移除多个用于模拟 Nintendo Switch 游戏的开源模拟器项目,其中包括 Suyu、Nzu、Uzuy、Torzu、Sudachi 和 Yuzu-vanced 等。这些模拟器均被指控包含绕过任天...

VIM配置整理

一、基本配色set number set showcmd set incsearch set expandtab set showcmd set history=400 set autoread set ffs=unix,mac,dos set hlsearch set shiftwidth=2 s...

Solid State Logic 发布低保真数字失真插件 Digicrush

Solid State Logic 宣布推出低保真数字失真插件 Digicrush ,他们最新的创意工具具有经典数字失真的粗糙、低保真特性,完美模拟早期数字音频的衰减和伪影。Digicrush 充满怀旧气息,深受经典数字采样器和效果器的影响,具有内置抖动、可调比特深度和采样率降低功能,是为音轨添加复...

Vue Router 4 路由操作 - 路由导航

路由导航分为 声明式导航 和 编程式导航。通过 <router-link to="..."> 标签跳转的方式为声明式导航。通过 路由实例对象(router.push(...))跳转的为编程式导航。导航到不同的位置想要导航到不同的URL,使用 router.push 方法。...