异步编程——@Async与@EnableAsync使用

文章目录

    • 使用思路
    • 基本使用规范
    • 常见问题——@Async无效
    • 常见问题——添加@EnableAsync注解后接口404

使用思路

异步场景及优势在此不多赘述。异步思路无非是在原本请求链路执行到某个环节时,将部分无需同步执行的操作交由主线程以外的其它线程执行。因此针对标题中两个注解的使用,我们常常会将异步执行内容单独封装一个方法并通过@Async修饰,然后在启动类/配置类(在异步方法所在类等其它地方也行,但规范要求是写在这两处)开启@EnableAsync

@SpringBootApplication
@EnableAsync
@ComponentScan(value = {"com.ivan.*"})
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}
}
public interface DemoService {String testOne() throws InterruptedException;String testTwo() throws InterruptedException;String testThree();
}
@RestController
@RequestMapping("/test")
public class DemoServiceImpl implements DemoService {@AutowiredApplicationContext applicationContext;@Resource@Lazyprivate DemoServiceImpl demoServiceImpl;@Override@GetMapping("/test_one")public String testOne() throws InterruptedException {//获取HelloService代理对象DemoServiceImpl bean = applicationContext.getBean(DemoServiceImpl.class);System.out.println("当前对象是否是代理对象:" + AopUtils.isAopProxy(bean));System.out.println("是否是cglib代理对象:" + AopUtils.isCglibProxy(bean));System.out.println("是否是jdk代理对象:" + AopUtils.isJdkDynamicProxy(bean));System.out.println(bean == this);//调用代理对象的异步方法bean.asyncMethod();return LocalDateTime.now().toString();}@Override@GetMapping("/test_two")public String testTwo() throws InterruptedException {
//        asyncMethod();System.out.println("当前对象是否是代理对象:" + AopUtils.isAopProxy(demoServiceImpl));System.out.println("是否是cglib代理对象:" + AopUtils.isCglibProxy(demoServiceImpl));System.out.println("是否是jdk代理对象:" + AopUtils.isJdkDynamicProxy(demoServiceImpl));demoServiceImpl.asyncMethod();return LocalDateTime.now().toString();}@Override@GetMapping("/test_three")public String testThree() {new Thread(() -> {try {Thread.sleep(10000);System.out.println("睡眠结束");} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();return LocalDateTime.now().toString();}@Async//不能声明为private//返回值只能为void或者Futurepublic void asyncMethod() throws InterruptedException {Thread.sleep(10000);System.out.println("睡眠结束");}
}

基本使用规范

  • @Async标注的异步方法,返回值只能为void或者Future,且方法不能声明为private,否则注解会失效。当其它线程调用这个方法时,就会开启一个新的子线程去异步处理该业务逻辑。

    切记:异步方法返回值为Future时,在调用方法的同时不要直接.get(),否则虽然开启了额外的线程,但主方法其实也堵塞在get()这行代码了,相当于就还是同步方法了。应当先调用异步方法返回Future<Object>在通过Future对象.get()获取结果数据

  • 使用此注解的方法的类对象,必须是spring管理下的bean对象 (如被@Service、@Component等修饰的Bean对象)
  • @Async注解还可用于修饰类,表示该类中的所有方法都是异步的
  • 在Spring项目中需要进行异步编程时,一定要开启异步。在启动类/配置类添加@EnableAsync

常见问题——@Async无效

  • 最常见情况——忘记加@EnableAsync注解
  • @Async标注的异步方法声明为private
  • 没有走Spring的代理类。(即Service里面方法A调用方法B,会不生效!!) 方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的,需要先获取其代理类,通过代理类调用异步方法——异步方法所在类使用了异步注解@Async 但是没有实现接口的时候,代码底层走 Cglib 动态代理,DemoServiceImpl控制类注入到 SpringMVC 容器中。Cglib 动态代理生成的代理对象是采用继承目标对象(DemoServiceImpl)的模式生成代理类的,而目标对象(DemoServiceImpl)中有@RestController 注解,所以注解会被继承过来,这样Cglib 生成的代理对象就可以注入到SpringMVC 容器中。因为@Async注解方法与控制类在同一个类中导致没有走代理类,所以@Async 注解失效。

    解决方法一:新建一个类,将@Async标注的异步方法放入该类
    解决方法二:从spring上下文中取得代理对象DemoServiceImpl bean = applicationContext.getBean(DemoServiceImpl.class);
    解决方法三: 在同一个类内部使用self-invocation的方式来调用被@Async修饰的方法
    @Resource
    @Lazy
    private DemoServiceImpl demoServiceImpl;

常见问题——添加@EnableAsync注解后接口404

异步方法所在类实现了接口且使用了异步注解@Async,代码底层会走 JDK 动态代理,导致 OrderServiceImpl 控制类没有注入到 SpringMVC 容器中。因为 JDK 动态代理技术是基于接口实现的,而接口中没有@RestController注解,所以导致代理对象无法注册到SpringMVC容器中。DemoServiceImpl做为代理类实现 DemoService接口,代理类(DemoServiceImpl)发现 DemoService接口上面没有 RestController 注解,所以导致了代理类(DemoServiceImpl)不会注入到SpringMVC容器中。

  • @Async标注的异步方法所在类实现了接口并重写了方法且@EnableAsync注解没有手动注明属性proxyTargetClass = true

    解决方法:@EnableAsync(proxyTargetClass = true)

Spring源码:

/**  初始化 bean 对象* Detects handler methods at initialization.* @see #initHandlerMethods*/@Overridepublic void afterPropertiesSet() {initHandlerMethods();}/*** Scan beans in the ApplicationContext, detect and register handler methods.* @see #getCandidateBeanNames()  获取到所有的 bean 对象* @see #processCandidateBean* @see #handlerMethodsInitialized*/protected void initHandlerMethods() {for (String beanName : getCandidateBeanNames()) {if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {processCandidateBean(beanName);}}handlerMethodsInitialized(getHandlerMethods());}
/*** Determine the type of the specified candidate bean and call* {@link #detectHandlerMethods} if identified as a handler type.* <p>This implementation avoids bean creation through checking* {@link org.springframework.beans.factory.BeanFactory#getType}* and calling {@link #detectHandlerMethods} with the bean name.* @param beanName the name of the candidate bean* @since 5.1* @see #isHandler* @see #detectHandlerMethods*/protected void processCandidateBean(String beanName) {Class<?> beanType = null;try {beanType = obtainApplicationContext().getType(beanName);}catch (Throwable ex) {// An unresolvable bean type, probably from a lazy bean - let's ignore it.if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex);}}if (beanType != null && isHandler(beanType)) {detectHandlerMethods(beanName);}}
/*** {@inheritDoc} 判断类上面是否有 Controller、RequestMapping 注解。* <p>Expects a handler to have either a type-level @{@link Controller}* annotation or a type-level @{@link RequestMapping} annotation.*/@Overrideprotected boolean isHandler(Class<?> beanType) {return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));}

参考文章
【异步任务】@Async注解使用方法及注解失效解决办法
SpringBoot中@EnableAsync和@Async注解的使用
@Async 注解失效解析

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

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

相关文章

代码随想录算法训练营第7天 | 454. 四数相加 II ,383. 赎金信 ,15. 三数之和 ,18. 四数之和

哈希知识基础 文章链接&#xff1a;https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html#%E5%93%88%E5%B8%8C%E8%A1%A8 454. 四数相加 II 题目链接&#xff1a;https://leetcode.cn/problems/4sum-ii/description/ 思路:哈希…

Linux安装Rdkafka PHP 扩展(Kafka使用教程)

以是centos为例 #可以查看php版本 php -v#查看php安装的扩展库 php -m 1、首先&#xff0c;确保你已经安装了 PHP 和相关的开发工具。你可以使用以下命令来安装它们&#xff1a; sudo yum install php-devel 中间会问你是否ok&#xff0c;输入y回车&#xff0c;出现complete…

pycharm debug显示的变量过多

问题&#xff1a; https://blog.csdn.net/Hodors/article/details/117535731 解决方法&#xff1a; 把"Show console variables by default"前面的勾取消掉就行 参考&#xff1a; https://stackoverflow.com/questions/48969556/hide-console-variables-in-pychar…

数据结构——二叉树(先序、中序、后序及层次四种遍历(C语言版))超详细~ (✧∇✧) Q_Q

目录 二叉树的定义&#xff1a; *特殊的二叉树&#xff1a; 二叉树的性质&#xff1a; 二叉树的声明&#xff1a; 二叉树的先序遍历&#xff1a; 二叉树的中序遍历&#xff1a; 二叉树的后序遍历&#xff1a; 二叉树的层序遍历&#xff1a; 二叉树的节点个数&#xff1a; 二叉…

使用netdxf(C#)框架实现dxf文件读取与导出坐标

使用netdxf&#xff08;C#&#xff09;框架实现dxf文件读取与导出坐标 一、新建窗体应用程序DxfToolDemo&#xff0c;将默认的Form1重命名为FormDxfTool 窗体FormDxfTool.Designer.cs设计器源程序如下&#xff1a; namespace DxfToolDemo {partial class FormDxfTool{/// <…

x-cmd pkg | magic-wormhole - (魔法虫洞)文件传输工具

目录 简介首次用户功能特点竞品和相关作品进一步探索 简介 magic-wormhole 是一个用于在两台计算机之间安全传输文件的工具。它通过创建一个临时的点对点连接&#xff0c;允许用户将文件或文本从一台计算机发送到另一台计算机。 它使用 PAKE 这一系列的加密算法&#xff0c;通…

扫地机行业研究:预计2028年将达到78.51亿美元

吸尘器、扫地机器人、洗地机为清洁电器中最亮眼的三大品类。吸尘器主要用来吸尘&#xff0c;扫地机的主要作用也是用于除尘&#xff0c;具备扫拖一体功能的扫地机&#xff0c;干湿混合垃圾暂时做不到干净清理。洗地机集齐了“吸、拖、洗”三种功能为一体&#xff0c;并且具备自…

消息队列-RockMQ-定时延时发送消息

定时延时发送消息 任务需要延迟一段时间再进行处理。 生产者 public class Producer {public static void main(String[] args) throws Exception {DefaultMQProducer producer new DefaultMQProducer("producer_group");producer.setNamesrvAddr("ip:9876&q…

【Python 数据分析】数据预处理:z-score 标准化、min-max 归一化、数据缺失值处理、数据重复处理

目录 简述 / 前言1. z-score 标准化2. min-max 归一化3. 数据缺失值处理4. 数据重复处理 简述 / 前言 本篇文章分享数据分析中最重要的一个步骤&#xff1a;数据预处理。我们在做数据分析之前&#xff0c;都需要采集很多数据&#xff0c;这些数据可能是从官网下载的&#xff0…

【docker-compose】【nginx】内网环境https配置

目录 1、openssl生成自签名证书和私钥2、nginx.conf配置ssl3、docker-compose挂载 1、openssl生成自签名证书和私钥 在部署服务器上&#xff0c;新建cert目录&#xff0c;执行以下指令&#xff0c;然后生成.crt和.key文件 openssl req -newkey rsa:2048 -nodes -keyout rsa_pri…

linux yum仓库

yum是基于rpm包构建的软件更新机制&#xff0c;能够自动解决软件包之间的依赖关系。 常用命令 查询 yum list [软件名] 显示可用的安装包&#xff0c;如果不加软件名则显示所有的可用包 yum info [软件名] 显示安装包的详细信息 如果不加软件名是显示所有包…

精灵图集的使用

什么是精灵图集 是一种将多个图片合并为一个大图片的资源。 为什么使用图集 纹理的长或宽不能恰好符合2的幂次(通常是UI资源) Unity使用非2的幂纹理大小&#xff0c;会稍微多一些内存并且GPU采样速度可能更慢 如果平台或 GPU 不支持 NPOT 纹理大小&#xff0c;Unity 会对纹理…

2024年【上海市安全员B证】考试试卷及上海市安全员B证复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 上海市安全员B证考试试卷根据新上海市安全员B证考试大纲要求&#xff0c;安全生产模拟考试一点通将上海市安全员B证模拟考试试题进行汇编&#xff0c;组成一套上海市安全员B证全真模拟考试试题&#xff0c;学员可通过…

海外短剧APP小程序开发 随心随意畅享大片

随着智能手机的普及和网络的高速发展&#xff0c;短剧APP已经成为当今热门的观影方式。作为一种全新的观影体验&#xff0c;海外短剧APP以其丰富多样的内容吸引了大量用户。本文将为您介绍海外短剧APP开发的相关知识和其所带来的优势&#xff0c;以及市场前景和发展趋势。 海外…

jsonschema,一个超强的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超强的 Python 库 - jsonschema。 Github地址&#xff1a;https://github.com/python-jsonschema/jsonschema JSON&#xff08;JavaScript Object Notation&#xff09;是…

MySQL 多版本并发控制 MVCC

MVCC出现背景 事务的4个隔离级别以及对应的三种异常 读未提交&#xff08;Read uncommitted&#xff09; 读已提交&#xff08;Read committed&#xff09;&#xff1a;脏读 可重复读&#xff08;Repeatable read&#xff09;&#xff1a;不可重复读 串行化&#xff08;Se…

.NET领域最硬核的gRPC 核心能力一把梭

前言&#xff0c;本文定位为.NET方向 grpc核心能力一把梭&#xff0c;全篇是姿势性和结论性的展示&#xff0c; 方便中高级程序员快速上手.NET Grpc。 有关grpc更深层次的前世今生、底层原理、困惑点释疑请听下回分解&#xff0c; 欢迎菜鸟老鸟们提出宝贵意见。 grpc宏观目标&…

跨平台进程/任务管理服务——Meproc的配置

配置 Meproc的配置非常简单&#xff0c;只有以下几个配置选项。 Conf [ip: 0.0.0.0,port: 8606,log_level: debug,log_dir: /tmp,web: [ip: 127.0.0.1,port: 8606,],bootstrap_cmd: , ];ip 是 Meproc 服务监听 HTTP 请求的地址。port 是Meproc服务监听HTTP请求的端口。log_l…

「Vue3面试系列」Vue 3.0中如果想实现一个 Modal组件应该怎么设计?

文章目录 一、组件设计二、需求分析三、实现流程目录结构组件内容实现 API 形式事件处理其他完善 一、组件设计 组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念&#xff08;组件&#xff09;来实现开发的模式 现在有一个场景&#xff0c;点击新增与编辑都弹框出来进…

Msql 8.0.3X my.cnf配置字典查询

Msql 8.0.3X my.cnf配置字典查询 ########################################################################### ## my.cnf for MySQL 8.0.x ## 注意&#xff1a; …