我接触异步概念最早的时候是在大学学习前端中,是一个很老的技术叫Ajax。异步编程很重要!很重要!很重要!在接口性能优化中我常用“sql优化、业务优化、算法优化”三把斧。其中“业务优化”中有“是否有可以异步进行的”这么一小则。今天的主题我们来看看Spring中相关异步中异常的那点事。
本文不是异步入门,默认读者有初步的异步知识。还不懂异步的读者请先网上查找相关资料先了解。
异步方法有两种形式:
CompletableFuture是个好东西,网上资料也很多。推荐读者学习!
这两种方式的不同,导致了异步方法中异常管理不同。在有返回值的异步方法,调用者可以在调用get阻塞时捕获异步方法中的抛出的异常并进行处理。但是对于无返回值的异步方法,则不能如此了。那我们该怎么办呢?
我们先来看一下异步的例子。定义一个异步任务组件并交由spring管理
@Component
@Slf4j
public class AsyncTask {
/**
* 有返回值的异步方法
*/
@Async("honeyAsyncExecutor")
public CompletableFuture<Integer> asyncFuture() throws InterruptedException {
log.info("start async task");
Thread.sleep(1000)
// 故意抛出异常
int a = 1 % 0;
log.info("end async task");
return CompletableFuture.completedFuture(2);
}
/**
* 无返回值的异步方法
*/
@Async("honeyAsyncExecutor")
public void async() throws InterruptedException {
log.info("start async task");
Thread.sleep(1000);
// 故意抛出异常
int a = 1 % 0;
log.info("end async task");
}
}
测试类
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class AsyncTest {
@Autowired
private AsyncTask asyncTask;
@Test
public void asyncTest() throws InterruptedException {
log.info("start.....");
CompletableFuture<Integer> future = asyncTask.asyncFuture();
log.info("start main bs");
Thread.sleep(2000);
log.info("main bs end...");
log.info("start request the result");
try {
Integer integer = future.get();
log.info(String.valueOf(integer));
} catch (ExecutionException exception) {
log.info("catch the exception");
}
}
}
在结果中我们成功捕获了异常并进行了处理。注意:异步方法中抛出的异常会被包装成ExecutionException。
我们接着看一下没有返回值的异常该怎么捕获并处理
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class AsyncTest {
@Autowired
private AsyncTask asyncTask;
@Test
public void testAsync() throws InterruptedException {
log.info("start.....");
asyncTask.async();
log.info("start main bs");
Thread.sleep(2000);
log.info("main bs end...");
}
}
结果中看到了SimpleAsyncUncaughtExceptionHandler这么个类。我们具体看一下这个类。
这个类是spring默认提供的针对没有返回值抛出异常时捕获到异常后,仅仅是打印,其他啥都没干。
public class SimpleAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
private static final Log logger = LogFactory.getLog(SimpleAsyncUncaughtExceptionHandler.class);
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
if (logger.isErrorEnabled()) {
logger.error("Unexpected exception occurred invoking async method: " + method, ex);
}
}
}
相信读者看到这里,应该懂该怎么针对性处理无返回值异步方法的异常了。就是自定义一个我们的AsyncUncaughtExceptionHandler 。但是在这里,博主并不推荐直接像spring那样实现AsyncUncaughtExceptionHandler 接口来提供我们的异步未捕获异常处理器。如果我们使用异步,我们要养成这么一个良好习惯:我们要根据我们系统的运行情况、配置情况等配置AsyncExecutor。所以比较好的做法是实现AsyncConfigurer 接口,在接口里提供AsyncExecutor,并提供上面的AsyncUncaughtExceptionHandler 。并在异步方法上面的异步注解指定Executor。
getAsyncExecutor前面为什么加个@Bean是为了可以给@Async指定Executor
@Slf4j
@Configuration
public class HoneyAsyncConfigurer implements AsyncConfigurer {
@Bean("honeyAsyncExecutor")
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(16);
executor.setQueueCapacity(64);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("HoneyAsyncThread-");
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (Throwable ex, Method method, Object... params) -> {
String errorBuilder = "Async execution error on method:" + method.toString() + " with parameters:"
+ Arrays.toString(params);
log.error(errorBuilder);
};
}
}
这里博主也没进行什么特殊处理,为了演示,仅仅是打印而已。在博主的Honey-OSS存储服务中,针对异步上传中也有涉及没有没有返回值的异步方法,在遇到预期中的异常时(像网络导致的链接异常)会利用重试机制进行重试。
说到这个重试,博主封装了基于注解的重试机制工具。后面分享出来。
- 本文就到此结束了,我们下文见,谢谢
- github: honey开源系列组件作者
原网址: 访问
创建于: 2023-10-19 15:27:17
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论