前言

SpringBoot想必大家都用过,但是大家平时使用发布的接口大都是同步的,那么你知道如何优雅的实现异步呢?

这篇文章就是关于如何在Spring Boot中实现异步行为的。但首先,让我们看看同步和异步之间的区别。

  • 同步编程:在同步编程中,任务一次执行一个,只有当一个任务完成时,下一个任务才会被解除阻塞。
  • 异步编程:在异步编程中,可以同时执行多个任务。您可以在上一个任务完成之前转到另一个任务。

Spring Boot中,我们可以使用@Async注解来实现异步行为。

欢迎关注个人公众号【JAVA旭阳】交流沟通

实现步骤

  1. 定义一个异步服务接口AsyncService.java
public interface AsyncService {

    void asyncMethod() throws InterruptedException;

    Future<String> futureMethod() throws InterruptedException;
}
  1. 实现定义的接口AsyncServiceImpl.java
@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService { @Async
@Override
public void asyncMethod() throws InterruptedException {
Thread.sleep(3000);
log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
} @Async
@Override
public Future<String> futureMethod() throws InterruptedException {
Thread.sleep(5000);
log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
return new AsyncResult<>("task Done");
}
}
  • AsyncServiceImpl 是一个 spring 管理的 bean
  • 您的异步方法必须是公共的,而且是被@Async注解修饰。
  • 返回类型被限制为 voidFuture
  1. 定义一个控制器AsyncController.java
@EnableAsync
@RestController
@Slf4j
public class AsyncController {
@Autowired
AsyncService asyncService; @GetMapping("/async")
public String asyncCallerMethod() throws InterruptedException {
long start = System.currentTimeMillis();
log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
asyncService.asyncMethod();
String response = "task completes in :" +
(System.currentTimeMillis() - start) + "milliseconds";
return response;
} @GetMapping("/asyncFuture")
public String asyncFuture() throws InterruptedException, ExecutionException {
long start = System.currentTimeMillis();
log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
Future<String> future = asyncService.futureMethod();
// 阻塞获取结果
String taskResult = future.get();
String response = taskResult + "task completes in :" +
(System.currentTimeMillis() - start) + "milliseconds";
return response;
}
}
  • 关键点,需要添加启用异步的注解@EnableAsync ,当然这个注解加在其他地方也ok得。
  • 当外部调用该接口时,asyncMethod() 将由默认任务执行程序创建的另一个线程执行,主线程不需要等待完成异步方法执行。
  1. 运行一下

现在我们运行一下看看,是不是异步返回的。

  • 可以看到调用/async接口,最终一步调用了方法。

  • 调用/asyncFuture,发现返回5秒多,难道不是异步的吗?其实也是异步的,看日志可以看出来,只不过我们返回的是Future,调用Futrue.get()是阻塞的。

自定义异步任务执行器和异常处理

我们现在看看如果异常方法中报错了会怎么样?修改异步代码如下所示,会抛运行时异常:

再次执行异步接口,如下所示,会使用默认的线程池和异常处理。

我们也可以自定义异步方法的处理异常和异步任务执行器,我们需要配置 AsyncUncaughtExceptionHandler,如下代码所示:

@Configuration
public class AsynConfiguration extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new
ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(4);
executor.setThreadNamePrefix("asyn-task-thread-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler
getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() { @Override
public void handleUncaughtException(Throwable ex,
Method method, Object... params) {
System.out.println("Exception: " + ex.getMessage());
System.out.println("Method Name: " + method.getName());
ex.printStackTrace();
}
};
}
}

再次运行,得到的结果如下:

@Async如何工作的?

必须通过使用 @EnableAsync注解注解主应用程序类或任何直接或间接异步方法调用程序类来启用异步支持。主要通过代理模式实现,默认模式是 Proxy,另一种是 AspectJ。代理模式只允许通过代理拦截调用。永远不要从定义它的同一个类调用异步方法,它不会起作用。

当使用 @Async对方法进行注解时,它会根据“proxyTargetClass”属性为该对象创建一个代理。当 spring 执行这个方法时,默认情况下它会搜索关联的线程池定义。上下文中唯一的 spring 框架 TaskExecutor bean 或名为“taskExecutor”的 Executor bean。如果这两者都不可解析,默认会使用spring框架SimpleAsyncTaskExecutor来处理异步方法的执行。

总结

在本文中,我们演示了在 spring boot 中如何使用 @Async 注解和异步方法中的异常处理实现异步行为。我们可以在一个接口中,需要访问不同的资源,比如异步调用各个其他服务的接口,可以使用@Async,然后将结果通过Future的方式阻塞汇总,不失为一个提高性能的好方法。

欢迎关注个人公众号【JAVA旭阳】交流沟通

Spring Boot中如何优雅地实现异步调用?的更多相关文章

  1. spring boot 学习(十一)使用@Async实现异步调用

    使用@Async实现异步调用 什么是”异步调用”与”同步调用” “同步调用”就是程序按照一定的顺序依次执行,,每一行程序代码必须等上一行代码执行完毕才能执行:”异步调用”则是只要上一行代码执行,无需等 ...

  2. spring boot中使用@Async实现异步调用任务

    本篇文章主要介绍了spring boot中使用@Async实现异步调用任务,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 什么是“异步调用”? “异步调用”对应的是“同步 ...

  3. Spring Boot中使用@Async实现异步调用

    在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数,为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsyn ...

  4. Spring Boot中实现异步调用之@Async

    一.什么是异步调用 “异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行:异步调用指程序在顺序执行时,不等待异步调用 的语句返回结果 ...

  5. 56. spring boot中使用@Async实现异步调用【从零开始学Spring Boot】

    什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执 ...

  6. Spring Boot中使用@Async实现异步调用,加速任务的执行!

    什么是"异步调用"?"异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行 ...

  7. 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  8. Spring Boot中使用Spring-data-jpa让数据访问更简单、更优雅

    在上一篇Spring中使用JdbcTemplate访问数据库中介绍了一种基本的数据访问方式,结合构建RESTful API和使用Thymeleaf模板引擎渲染Web视图的内容就已经可以完成App服务端 ...

  9. 利用 Spring Boot 中的 @ConfigurationProperties,优雅绑定配置参数

    使用 @Value("${property}") 注释注入配置属性有时会很麻烦,尤其是当你使用多个属性或你的数据是分层的时候. Spring Boot 引入了一个可替换的方案 -- ...

  10. Spring Boot中使用MyBatis注解配置详解(1)

    之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...

随机推荐

  1. Linux 使用Apache服务部署静态网站

    网站服务程序 我们平时访问的网站服务就是Web网络服务,一般是指允许用户通过浏览器访问到互联网中各种资源的服务.如图所示,Web网络服务是一种被动访问的服务程序,即只有接收到互联网中其他主机发出的请求 ...

  2. 在使用admin后台管理,添加或者修改数据库时,出现错误,no such table: main.auth_user__old

    在使用admin后台管理,添加或者修改数据库时,出现错误,no such table: main.auth_user__old. Django是2.0.9的版本,python是3.8.0 上述错误是因 ...

  3. 使用cpu-z简单看处理器,显卡等

    心血来潮想了解一下自己的电脑.在网上搜索cpu-z,大小只有几百kb.下面以我自己电脑为例,上图: 某些地方我也不是很了解,不太了解的我就直接跳过了.在网上查阅相关资料后,有下面的认识: (1)处理器 ...

  4. chap3第三小组总结

      本周我们第三小组在张庆老师的带领下,走向编程的新一扇大门--分支结构.   我们第三小组是线下聚在一起学习,这样可以使我们的学习效率大大提高,我们在线下学习可以让我们的小组长更方便的指导我们的学习 ...

  5. FastReport报表金额数字转大写问题

    在使用FastReport报表打印的时候涉及到财务结算金额时,会用到大写,系统保存的都为数字,将数字转换为大写没有默认的系统内置函数,经过查阅资料,可通过对FastReport的页面设计代码修改实现: ...

  6. sdio/mmc/sd笔记

    [SDIO] SD card 初始化及常用命令解析 https://blog.csdn.net/u010443710/article/details/107014873 cmd0命令,是单向命令,ho ...

  7. Vant+小程序+购物车实例

    图片实例,看是否是您所需要的喔.... 扫码小程序可看实例操作,有啥问题也可扫码加群,很希望可以帮助到你喔!           HTML部分: <view class="cart&q ...

  8. Coder vs Programmer: Difference You Should Know

    In this tech-driven world, you may have heard the terms 'coder' and 'programmer' used interchangeabl ...

  9. C++ PTA 本题要求实现一个计算m和n之间所有整数的和

    6-2  2020mhb_函数_求和 (10分) 本题要求实现一个计算m和n之间所有整数的和(求和时需要将m和n也加入到和中)的函数.注意:如果m<=n则计算m到n的所有整数之和,如果m> ...

  10. 如何在VM虚拟机里建立Linux操作系统

    1.新建虚拟机 2.选择典型安装 3.选择稍后安装操作系统 4.选择Linux操作系统和CentOS 7 64位 5.选择文件路径 注意:建议每台虚拟机单独文件夹保存,并且此处路径最好不要有中文出现 ...