Spring--@Async解析

一、@Async 简介

从Spring3开始提供了@Async注解,被该注解标注的方法,Spring底层会新建一个线程池或者使用已有的线程池中的线程去异步的执行被标注的方法。

二、@Async 工作原理

@Async与@Transactional 工作原理基本是一样的,也是通过Spring AOP动态代理去实现的。Spring容器启动初始化bean时,判断类中是否使用了@Async注解,如果使用了则为其创建代理对象,在线程调用@Async注解标注的方法时,通过代理对象执行切入点处理器invoke方法,将方法的执行提交给线程池中的另外一个线程来处理,从而实现了异步执行。

三、在SpringBoot中的使用

@Async在SpringBoot中的使用还是挺简单的,只需要下面两部操作就可以实现方法的异步调用。

1. 在启动类上使用@EnableAsync注解
@SpringBootApplication
@EnableAsync
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
2. 将需要异步执行的方法所在的类注入到spring容器,并在异步的方法上添加@Async注解
@Component
public class AsyncTest {/***  无返回值调用*/@Asyncpublic void asyncDoSomething(){// 具体业务逻辑处理……}/*** 有返回值的调用,使用Future来接收异步任务执行的结果* 对于返回值是Future,需要我们在方法中捕获异常并处理,或者在调用方在调用Futrue.get时捕获异常进行处理* * @return*/@Asyncpublic Future<String> asyncDoSomethingToReturn() {Future<String> future;try {// 具体业务逻辑处理……future = new AsyncResult<String>("success");} catch (InterruptedException e) {future = new AsyncResult<String>("InterruptedException");} catch(IllegalArgumentException e){future = new AsyncResult<String>("IllegalArgumentException");}return future;}
}

四、@Async失效场景

  1. 非公有方法:注解标注方法修饰符为非public时,异步任务会失效。因为@Async是基于动态代理实现的,如果被@Async标注的方法的修饰符不是public的话,将不会对该bean进行代理对象创建或者不会对方法进行代理调用,从而也就无法将任务交由现场池中的某个线程去异步执行任务。
  2. final 修饰的方法:如果动态代理使用的是cglib实现的话,由于cglib实现动态代理的方式主要是靠运行期动态创建目标类的子类,从而无法创建代理对象,也就无法将任务交由现场池中的某个线程去异步执行任务。
  3. 类内部访问:在同一个类中调用被@Async方法调用时,也会因为在当前类中无法生成的代理对象来调用,只能调用实际的目标方法,也就无法将任务交由现场池中的某个线程去异步执行任务。

五、@Async 底层源码解析

5.1 @Async注解源码

在这里插入图片描述
从上面@Async注解源码可以看出,只有一个value属性,这个属性就是线程池Bean的名称,如果在注解中设置了这个值,则根据这个值从Spring容器中获取这个线程池的Bean去异步执行方法;如果没设置,则会使用默认的线程池去异步执行该方法。所以这里想要指定具体的线程池去异步执行方法的话,只需要在@Async(“taskExecutor”)中设置线程池的bean的名称当作注解的value属性值就好。

5.2 @EnableAsync注解源码

在这里插入图片描述

(1)根据上面@EnableAsync源码可以看出,该注解中使用了一个@Import注解导入了一个AsyncConfigurationSelector.class类。
在这里插入图片描述
(2)进入到AsyncConfigurationSelector类,可以看到该类继承了AdviceModeImportSelector抽象类,AdviceModeImportSelector抽象类又实现了ImportSelector接口。并且在selectImports()方法中根据不同的AdviceMode来选择和返回适当的导入语句。
在这里插入图片描述
(3)进入到ProxyAsyncConfiguration配置类中,可以看到会创建一个AsyncAnnotationBeanPostProcessor对象,并设置相关的属性后返回该对象。
在这里插入图片描述
(4)再进入到AsyncAnnotationBeanPostProcessor类中,有个setBeanFactory()方法,在这个方法中往BeanFactory容器中增加了一个AsyncAnnotationAdvisor增强器。
在这里插入图片描述
(5)进入这个AsyncAnnotationAdvisor增强器的构造函数可以看到,分别创建了一个通知以及切入点。
在这里插入图片描述
(6)在这个创建增强方法的的函数中,可以看到创建了一个拦截器,主要通过这个拦截器来拦截标注有@Async注解的方法。
在这里插入图片描述
(7)进入到AnnotationAsyncExecutionInterceptor拦截器,可以看到其继承了AsyncExecutionInterceptor,主要的拦截方法就在这个AsyncExecutionInterceptor父类的invoke()方法中。主要步骤也就下面三步:1. 获取线程池;2. 创建线程;3. 提交任务到线程去执行。
在这里插入图片描述
(8)看下获取线程池的处理逻辑。主要步骤是:1.先从缓存中去查找,如果缓存中存在线程池就直接返回这个线程池去使用;2.如果缓存中没找到再根据方法的@Async注解value值进行判断;3.方法的的@Async注解设置了value值,则把value的值当做线程池的bean名称去Spring容器中找到这个bean并返回去使用;4.如果方法的@Async注解没有设置了value值,则使用默认的线程池去调用。

在这里插入图片描述
(9)看下获取注解值的方法。主要逻辑就是先拿到方法的Async注解,再根据拿到的注解获取该注解的value属性值。在这里插入图片描述
(10)再看下使用默认线程池的方法。主要是先调用父类的getDefaultExecutor方法去获取线程池对象,如果能获取到就直接使用该线程池对象,如果获取不到就新建个SimpleAsyncTaskExecutor线程池对象。
在这里插入图片描述
进入SimpleAsyncTaskExecutor的execute方法去创建线程执行任务。
在这里插入图片描述
在doExecute()方法中每次都会创建一个线程去执行。
在这里插入图片描述

由于SimpleAsyncTaskExecutor是个简单的线程池,通过这个线程池创建的线程不能重复使用,且每次调用都会去创建一个线程,在高并发或者访问很频繁的场景并不适用,很容易造成系统线程资源耗尽,严重可能导致系统崩溃。所以在使用@Async注解去实现方法的异步调用时最好使用自定义线程池或者ThreadPoolTaskExecutor线程池去替换掉@Async注解默认的线程池。

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

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

相关文章

100天精通鸿蒙从入门到跳槽——第11天:TypeScript 知识储备:装饰器

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…

代码随想录 Leetcode150. 逆波兰表达式求值

题目&#xff1a; 代码(首刷看解析 2024年1月21日&#xff09;&#xff1a; class Solution { public:int evalRPN(vector<string>& tokens) {stack<long long> st; for (int i 0; i < tokens.size(); i) {if (tokens[i] "" || tokens[i] &qu…

AP5191 降压恒流 双灯 12V5A 一切一LED车灯汽车大灯驱动方案

AP5191是一款PWM工作模式,高效率、外围简 单、内置功率MOS管&#xff0c;适用于4.5-150V输入的高 精度降压LED恒流驱动芯片。输出功率150W&#xff0c; 电流6A。 AP5191可实现线性调光和PWM调光&#xff0c;线性调 光脚有效电压范围0.55-2.6V. AP5191 工作频率可以通过RT 外部…

win 下使用 cmd 运行 jar 包

1、使用 Win R 输入 cmd 命令打开命令提示符 2、在 cmd 窗口中输入以下命令 java -jar xxxxxx.jar 运行 jar 包&#xff0c;控制台出现中文乱码 原因是 windows 默认使用 GBK 编码格式&#xff0c;程序使用 UTF-8 编码格式 将编码格式改为 UTF-8 编码&#xff0c;在 cmd 窗…

JavaScript库jquery的使用方法

"写更少&#xff0c;做更多"是jquery的设计理念&#xff0c;jquery是一个兼容多浏览器的JavaScript库&#xff0c;利用jquery的语法设计能使开发更便捷。 网页添加jquery的方法:1.从jquery.com下载库&#xff1b;2.从CDN中载入库&#xff08;示例使用&#xff09;&a…

【遥感数字图像处理(朱文泉)】各章博文链接汇总及思维导图

遥感数字图像处理课程汇总 第0章 绪论第一章 数字图像基础第二章 数字图像存储与处理第三章 空间域处理方法第四章 变换域处理方法第五章 辐射校正第六章 几何校正第七章 图像去噪声第八章 图像增强第九章 感兴趣目标及对象提取第十章 特征提取与选择第十一章 遥感数字图像分类…

c++学习之IO流

目录 前言&#xff1a; 一&#xff0c;流的概念 二&#xff0c;c的io流 输入输出流 缓冲区的同步 文件流 文件的打开 文件读写自定义类型数据 字符流 1. 将数值类型数据格式化为字符串 2. 字符串拼接 3. 序列化和反序列化结构数据 前言&#xff1a; 在了解c的输入输…

SpringBoot异常处理和单元测试

学习目标 Spring Boot 异常处理Spring Boot 单元测试 1.SpringBoot异常处理 1.1.自定义错误页面 SpringBoot默认的处理异常的机制&#xff1a;SpringBoot 默认的已经提供了一套处理异常的机制。一旦程序中出现了异常 SpringBoot 会向/error 的 url 发送请求。在 springBoot…

c语言->学会offsetof宏计算结构体相对偏移量

前言 ✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青-CSDN博客 目的&#xff0c;学习offsetof宏计算结构体相对偏移量 1.offsetof宏 来我们看图…

vector讲解

在学习玩string后我们开始学习vector&#xff0c;本篇博客将对vector进行简单的介绍&#xff0c;还会对vector一些常用的函数进行讲解 vector的介绍 实际上vector就是一个数组的数据结构&#xff0c;但是vector是由C编写而成的&#xff0c;他和数组也有本质上的区别&#xff…

2.机器学习-K最近邻(k-Nearest Neighbor,KNN)分类算法原理讲解

2️⃣机器学习-K最近邻&#xff08;k-Nearest Neighbor&#xff0c;KNN&#xff09;分类算法原理讲解 个人简介一算法概述二算法思想2.1 KNN的优缺点 三实例演示3.1电影分类3.2使用KNN算法预测 鸢(yuan)尾花 的种类3.3 预测年收入是否大于50K美元 个人简介 &#x1f3d8;️&…

flink部署模式介绍

在一些应用场景中&#xff0c;对于集群资源分配和占用的方式&#xff0c;可能会有特定的需求。Flink 为各种场景提供了不同的部署模式&#xff0c;主要有以下三种&#xff0c;它们的区别主要在于&#xff1a; 集群的生命周期以及资源的分配方式&#xff1b;应用的 main 方法到…

XXL-Job的搭建接入Springboot项目(详细)

一、XXL-Job介绍 XXL-Job 是一款开源的分布式任务调度平台&#xff0c;由 Xuxueli&#xff08;徐雪里&#xff09;开发。它基于 Java 技术栈&#xff0c;提供了一套简单易用、高可靠性的任务调度解决方案。 XXL-Job 的主要作用是帮助开发者实现定时任务的调度和执行。它可以用…

2024年轻人返乡创业潮,外卖平台市场需求是怎么样的?

目前&#xff0c;县域经济正面临着几大利好。“返乡就业、返乡创业和告老还乡”现象越发普遍&#xff0c;这不仅在小县城中有所体现&#xff0c;同样在乡镇中也呈现出同样的趋势。一些产业链和工厂纷纷下沉到乡镇&#xff0c;带来了更多的就业机会。这不仅能够吸引年轻人回乡就…

Spring Boot 4.0:构建云原生Java应用的前沿工具

目录 前言 Spring Boot简介 Spring Boot 的新特性 1. 支持JDK 17 2. 集成云原生组件 3. 响应式编程支持 4. 更强大的安全性 5. 更简化的配置 Spring Boot 的应用场景 1. 云原生应用开发 2. 响应式应用程序 3. 安全性要求高的应用 4. JDK 17的应用 总结 作…

CRM系统--盘点五大CRM客户管理系统

在当今市场经济中&#xff0c;销售工作的重要性日益凸显&#xff0c;有效的客户管理成为了提升销售业绩的关键因素。面对日新月异的市场环境和客户需求的多样化&#xff0c;销售人员通常会面临以下问题&#xff1a; 接到了新的销售任务&#xff0c;该如何选择和确定目标客户&am…

API协议设计的十种技术

文章目录 前言一、REST二、GraphQL三、gRPC&#xff08;google Remote Procedure Calls&#xff09;四、Webhooks五、服务端的事件发送——SSE&#xff08;Server-sent Events&#xff09;六、EDI&#xff08;Electronic Data Interchange&#xff09;七、面向API 的事件驱动设…

Visual Studio2022实用使用技巧集

前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具&#xff0c;掌握一些Visual Studio实用的搜索、查找、替换技巧可以帮助我们大大提高工作效率从而避免996。 Visual Studio更多实用技巧 https://github.com/YSGStudyHards/DotNetGuide 代码和功能搜…

Verilog基础:强度建模与net型信号的多驱动问题(三)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 四、一般情况下的net型信号的线与组合&#xff08;线网多驱动&#xff09; 在Verilog基础&#xff1a;强度建模与net型信号的多驱动问题&#xff08;二&#xff0…

如何在Linux部署JumpServer堡垒机并实现远程访问本地服务

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…