深入浅出 Spring @Async 异步编程的艺术

目录

一、异步编程

二、@Async 介绍

2.1 @Async 使用

三、@Async 原理


一、异步编程

        在软件开发中,异步编程是非常关键的,尤其是构建高性能、高响应度的应用时。异步编程的主要优势在于它能够避免阻塞操作,提高程序的效率和用户体验。异步编程的应用场景:

  • 在 Web 应用中,服务器可以处理多个请求,而无需等待耗时的操作完成,将耗时的操作进行异步处理。
  • 高并发场景中,异步模型可以处理大量并发连接,而不会因为创建过多线程而导致系统资源耗尽。
  • 使用消息队列进行异步处理,避免影响服务的性能。

        而在 Spring 框架中,提供了 @Async 注解,一行代码就帮我们搞定了异步调用。Async 注解用起来简单高效,但是如果不对其底层实现做深入研究,难免有时候也会心生疑虑,甚至会因使用不当,遇见一些让人摸不着头脑的问题。

        下面就来一起探讨下 @Async 注解。

二、@Async 介绍

        @Async 是 Spring 框架中的一个注解,用于支持异步方法的执行。在 Spring 中,当你在一个类的方法上使用 @Async 注解时,Spring 会确保该方法在不同的线程中执行,而不是调用者所在的线程。这意味着方法的执行可以并行进行,从而提高了应用程序的性能,尤其是在处理耗时的任务时。

        下面是 @Async 注解的源码,很简单,只有一个 value 属性,从源码上可以看出,这个注解可以应用在方法上,也可以应用在类上。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {/*** A qualifier value for the specified asynchronous operation(s).* <p>May be used to determine the target executor to be used when executing* the asynchronous operation(s), matching the qualifier value (or the bean* name) of a specific {@link java.util.concurrent.Executor Executor} or* {@link org.springframework.core.task.TaskExecutor TaskExecutor}* bean definition.* <p>When specified on a class-level {@code @Async} annotation, indicates that the* given executor should be used for all methods within the class. Method-level use* of {@code Async#value} always overrides any value set at the class level.* @since 3.1.2*/String value() default "";}

2.1 @Async 使用

        @Async 的使用也很简单,只需要两步即可完成:

  1.  在配置类中首先添加 @EnableAsync 注解来启用异步支持。
  2. 在需要异步执行的方法上添加 @Async 注解。

        通过以上两步就可以使用异步任务执行了,默认情况下,Spring 使用一个简单的线程池来执行异步任务,但是可以再 @Async 注解中指定一个参数来使用自定义的线程池,例如:

@Async("myThreadPoolTaskExecutor")
public void task() {// Method implementation...
}

三、@Async 原理

         添加 @EnableAsync 注解后,服务启动时会触发一系列的配置和组件注册。@EnableAsync 部分源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {}

           通过 @Import 导入了 AsyncConfigrationSelector,AsyncConfigrationSelector 会根据配置模式创建一个 AsyncConfigure,有两种配置模式,分别创建两种不同的 AsyncConfigure。

  • PROXY:默认模式,使用 JDK 动态代理或 CGLIB 代理(取决于 proxyTargetClass 属性)。在这种模式下,AsyncConfigurationSelector 将会选择导入 ProxyAsyncConfiguration类,意味着将使用代理来拦截和处理异步方法调用。
  • ASPECTJ:如果应用程序使用了 AspectJ,在这种模式下,AsyncConfigurationSelector 选择导入一个与 AspectJ 相关的配置类。

        具体源码如下:

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME ="org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";@Override@Nullablepublic String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[] {ProxyAsyncConfiguration.class.getName()};case ASPECTJ:return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};default:return null;}}

        下面再来看下 ProxyAsyncConfiguration 类中做了哪些工作

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public AsyncAnnotationBeanPostProcessor asyncAdvisor() {Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();bpp.configure(this.executor, this.exceptionHandler);Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {bpp.setAsyncAnnotationType(customAsyncAnnotation);}bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));return bpp;}}

        这个类的核心方法是创建 AsyncAnnotationBeanPostProcessor 实例,这是处理 @Async 注解的关键组件。它负责解析 @Async 注解,并将异步方法调用转换成异步执行。它是 Spring AOP 的一部分,通过实现 BeanPostProcessor 接口和 Advisor 接口,AsyncAnnotationBeanPostProcessor 可以在 Spring 容器初始化期间对 Bean 进行后处理,以及定义切面(Aspect)来拦截异步方法的调用。     

          AsyncAnnotationBeanPostProcessor 会创建一个 AsyncAnnotationAdvisor,这时一个切面,用于拦截带有 @Async 注解的方法。

public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {@Overridepublic void setBeanFactory(BeanFactory beanFactory) {super.setBeanFactory(beanFactory);AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);if (this.asyncAnnotationType != null) {advisor.setAsyncAnnotationType(this.asyncAnnotationType);}advisor.setBeanFactory(beanFactory);this.advisor = advisor;}}

        AsyncAnnotationAdvisor 中包含了 Advice,即 AnnotationAsyncExecutionInterceptor

        当方法执行时会真正创建该方法的一个代理,这样当方法被调用时,就会被 AnnotationAsyncExecutionInterceptor 拦截,然后委托给线程池进行异步处理。

        总之,通过 @EnableAsync 配置和激活异步执行所需的基础设施,包括线程池、异常处理器、AOP 切面和动态代理,使得开发者能够在不需要关心底层细节的情况下编写异步方法。

往期经典推荐

高性能的秘密:揭秘Nginx如何支撑亿级流量网站_亿级流量nginx架构-CSDN博客

Sentinel与Nacos强强联合,构建微服务稳定性基石的重要实践_sentinel 整合nacos-CSDN博客

高并发架构设计模板-CSDN博客

TiDB高手进阶:揭秘自增ID热点现象与高级调优技巧_tidb 分布式自增id-CSDN博客

SpringBoot开箱即用魔法:深度解析与实践自定义Starter-CSDN博客

Spring循环依赖的成因与破局_spring为什么会有循环依赖的需求-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/44712.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

修BUG:程序包javax.servlet.http不存在

貌似昨晚上并没有成功在tomcat上面运行&#xff0c;而是直接运行了网页。 不知道为啥又报错这个。。。 解决方案&#xff1a; https://developer.baidu.com/article/details/2768022 就整了这一步就行了 而且我本地就有这个tomcat就是加进去了。 所以说啊&#xff0c;是不是&a…

eNSP公司管理的对象及策略

拓扑图[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 ) 实验需求 第一步&#xff1a;根据题目搭建拓扑图 其中交换机的型号为&#xff1a;S5700 防火墙设备为&#xff1a;USG6000V 第二步&#xff1a;启动防火墙设备 首先会让你输入密码&#xff0c;…

SQL MySQL定时器/事件调度器(Event Scheduler)

事件调度器&#xff08;Event Scheduler&#xff09;在MySQL数据库系统中是一个强大的功能组件&#xff0c;它允许用户定义一系列称为“事件”的数据库对象&#xff0c;这些事件在指定的时间或时间间隔自动执行预定义的SQL语句或操作。事件调度器通过维护一个时间计划表来管理这…

小抄 20240709

1 很多人做事&#xff0c;没有目标&#xff0c;没有主见&#xff0c;只是按照别人的指示去做&#xff0c;完全不清楚为什么去做。 你去问他为什么要做&#xff0c;他反而要和你急眼&#xff0c;觉得你在质疑他。 2 想要获得超出预期的成功&#xff0c;不是努力到极致&#x…

npm install报错:淘宝镜像证书过期

npm install报错&#xff1a;淘宝镜像证书过期 近期使用npm淘宝镜像新建项目或依赖时出现报错&#xff1a; npm ERR! request to https://registry.npm.taobao.org/xxx failed, reason: certificate has expired 错误原因&#xff1a; 早在 2021 年&#xff0c;淘宝就发文称…

【MySQL】常见的MySQL日志都有什么用?

MySQL日志的内容非常重要&#xff0c;面试中经常会被问到。同时&#xff0c;掌握日志相关的知识也有利于我们理解MySQL 底层原理&#xff0c;必要时帮助我们排查解决问题。 MySQL中常见的日志类型主要有下面几类(针对的是InnoDB 存储引擎): 错误日志(error log):对 MySQL 的启…

QScrollArea 设置最大的高度值

在 Qt 中&#xff0c;QScrollArea 是一个提供滚动视图的控件&#xff0c;允许用户查看大于当前视口尺寸的内容。如果你想要为 QScrollArea 设置一个最大的高度值&#xff0c;这通常不是直接通过 QScrollArea 的属性来设置的&#xff0c;而是需要调整其内容部件&#xff08;widg…

CentOS 6.5配置国内在线yum源和制作openssh 9.8p1 rpm包 —— 筑梦之路

CentOS 6.5比较古老的版本了&#xff0c;而还是有一些古老的项目仍然在使用。 环境说明 1. 更换国内在线yum源 CentOS 6 在线可用yum源配置——筑梦之路_centos6可用yum源-CSDN博客 cat > CentOS-163.repo << EOF [base] nameCentOS-$releasever - Base - 163.com …

新兴市场游戏产业爆发 传音以技术抢抓机遇 ​

随着年轻人口的增加以及互联网的普及,非洲、中东等新兴市场正迎来游戏产业的大爆发,吸引着全球游戏企业玩家在此开疆辟土。中国出海企业代表传音以新兴市场需求为中心,秉持本地化创新理念不断加强游戏等关键领域技术攻关凭借移动终端设备为全球玩家带来极致游戏体验,收获了消费…

就业平台小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;企业管理&#xff0c;企业类型管理&#xff0c;留言板管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;招聘信息&#xff0c;简历&#xff0c;我的…

2024年中欧班列累计开行1万列

新华社武汉7月10日电&#xff08;记者王自宸、樊曦&#xff09;今年第10000列中欧班列10日从武汉吴家山站开出&#xff0c;较去年提前19天破万列&#xff0c;累计发送货物108.3万标箱&#xff0c;同比增长11%&#xff0c;为保障产业链供应链稳定、促进中欧经贸往来注入新动能。…

MapReduce底层原理详解:大案例解析(第32天)

系列文章目录 一、MapReduce概述 二、MapReduce工作机制 三、Map&#xff0c;Shuffle&#xff0c;reduce阶段详解 四、大案例解析 文章目录 系列文章目录前言一、MapReduce概述二、MapReduce工作机制1. 角色与组件2. 作业提交与执行流程1. 作业提交&#xff1a;2. Map阶段&…

MATLAB中c2d函数用法

目录 语法 说明 示例 在MATLAB中&#xff0c;c2d函数用于将连续时间系统&#xff08;Continuous-Time System&#xff09;转换为离散时间系统&#xff08;Discrete-Time System&#xff09;。以下是c2d函数的基本语法、说明以及示例&#xff1a; 语法 sys_d c2d(sys_c, T…

【每天认识一个漏洞】spf邮件伪造漏洞

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 &#x1f3a3;漏洞危害 允许攻击者伪造发件人身份&#xff0c;从而发送钓鱼邮件或垃圾邮件&#xff0c;获取接收方的信任&am…

Spring Boot开发框架

Spring Boot是一个基于Spring框架的开源项目&#xff0c;旨在简化Spring应用的创建、配置和部署。它通过提供默认配置和一系列开箱即用的功能&#xff0c;帮助开发者快速构建生产级的Spring应用。以下是对Spring Boot的详细介绍&#xff1a; 1. 核心理念 1.1 快速入门 Sprin…

SQL 自定义函数

概念 自定义函数是用户根据自己的业务逻辑或计算需求创建的函数。这些函数可以接收一个或多个输入参数&#xff0c;执行一系列的操作&#xff08;如计算、数据处理、逻辑判断等&#xff09;&#xff0c;并最终返回一个值或结果集。自定义函数可以被多次重用&#xff0c;提高了…

C++:cv::boundingRect()函数解析

cv::boundingRect() 函数是 OpenCV 库中的一个函数&#xff0c;用于计算并返回一个点集的边界矩形。这个函数特别有用&#xff0c;当你已经找到了一些轮廓&#xff08;contours&#xff09;或者任何其他形状的点集&#xff0c;并希望获得一个能够包围这些点的最小矩形时。 函数…

编程什么叫f语言编程软件:深入解析F语言编程软件的概念与特性

编程什么叫f语言编程软件&#xff1a;深入解析F语言编程软件的概念与特性 在编程领域&#xff0c;各种编程语言和软件层出不穷&#xff0c;每种都有其独特的特点和适用场景。其中&#xff0c;F语言编程软件作为一种相对较为特殊的存在&#xff0c;引起了众多编程爱好者的关注。…

[leetcode]partition-list 分隔链表

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:ListNode* partition(ListNode* head, int x) {ListNode *smlDummy new ListNode(0), *bigDummy new ListNode(0);ListNode *sml smlDummy, *big bigDummy;while (head ! nullptr) {if (head->val &l…

YOLOv10改进 | 添加注意力机制 | 添加ACmix自注意力与卷积混合模型改善模型特征识别效率(包含二次创新PSA机制)

一、本文介绍 本文给大家带来的改进机制是ACmix自注意力机制的改进版本&#xff0c;它的核心思想是&#xff0c;传统卷积操作和自注意力模块的大部分计算都可以通过1x1的卷积来实现。ACmix首先使用1x1卷积对输入特征图进行投影&#xff0c;生成一组中间特征&#xff0c;然后根…