You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

作用

spring容器中实现bean方法的异步调用。 比如有个logService的beanlogservice中有个log方法用来记录日志当调用 logService.log(msg)的时候,希望异步执行,那么可以通过 @EnableAsync & @Async 来实现。

用法

  1. 需要异步执行的方法上面使用 @Async 注解标注若bean中所有的方法都需要异步执行可以直接将 @Async 加载类上。
  2. 将 @EnableAsync 添加在spring配置类上此时 @Async 注解才会起效。

常见2种用法

  1. 无返回值的
  2. 可以获取返回值的

无返回值的

!Snipaste_2023-02-19_15-42-08 9.png

有返回值的

!Snipaste_2023-02-19_15-42-08 10.png

案例

!Snipaste_2023-02-19_15-42-08 11.png !Snipaste_2023-02-19_15-42-08 12.png !Snipaste_2023-02-19_15-42-08 13.png 方法之间无关联的可以采用异步的方式,并行去获取,最终耗时为最长的那个方法,整体相对于同步的方式性能提升不少。

自定义异步执行线程池

方式1、在Spring容器中定义一个线程池类型的beanbean名称必须是taskExecutor

!Snipaste_2023-02-19_15-42-08 14.png

方式二、实现接口AsyncConfigurer

!Snipaste_2023-02-19_15-42-08 15.png

自定义异常处理

异常处理分2种情况

  1. 当返回值是Future的时候方法内部有异常的时候异常会向外抛出可以对Future.get采用try..catch来捕获异常 !Snipaste_2023-02-19_15-42-08 16.png
  2. 当返回值不是Future的时候可以自定义一个bean实现AsyncConfigurer接口中的getAsyncUncaughtExceptionHandler方法返回自定义的异常处理器 !Snipaste_2023-02-19_16-27-02.png

线程池隔离

什么是线程池隔离?

一个系统中可能有很多业务,比如充值服务、提现服务或者其他服务,这些服务中都有一些方法需要异 步执行,默认情况下他们会使用同一个线程池去执行,如果有一个业务量比较大,占用了线程池中的大 量线程,此时会导致其他业务的方法无法执行,那么我们可以采用线程隔离的方式,对不同的业务使用不同的线程池,相互隔离,互不影响。@Async 注解有个 value 参数用来指定线程池的bean名称方法运行的时候就会采用指定的线程池来执行目标方法。

使用步骤

  1. 在Spring容器种自定义线程池相关的bean
  2. @Async("线程池bean名称")

!Snipaste_2023-02-19_16-27-02 1.png !Snipaste_2023-02-19_16-27-02 2.png

原理

内部使用aop实现的@EnableAsync会引入一个bean后置处理器AsyncAnnotationBeanPostProcessor 将其注册到spring容器这个bean后置处理器在所有bean创建过程中判断bean的类上是否有@Async注解或者类中是否有@Async标注的方法如果有会通过aop给这个bean生成代理对象会在代理对象中添加一个切面org.springframework.scheduling.annotation.AsyncAnnotationAdvisor这个切面中会引入一个拦截器AnnotationAsyncExecutionInterceptor方法异步调用的关键代码就是在这个拦截器的invoke方法中实现的。