springboot中的异步任务
在springboot项目中可以通过@EnableAsync+@Async的方式简化异步操作,下文使用springboot:3.2.1 源码分析
若一个bean中的公共方法上标注了@Async,在系统启动时,会给这个类创建一个代理对象,并将该代理对象作为bean注册到spring容器中
当调用带有@Async注解的方法时,实际上是调用了代理对象的方法,在代理对象的方法中将真正的方法交给线程池去执行
原理分析
代理方法执行时,AsyncExecutionInterceptor#invoke
调用determineAsyncExecutor()
方法获取异步执行器,然后将真实方法的执行交给异步执行器
获取@Async指定的异步执行器,若未指定,则使用默认的异步执行器
获取默认的异步执行器
- 默认的异步执行器类型是
ThreadPoolTaskExecutor
,由org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations.TaskExecutorConfiguration向spring容器中注册- 且核心线程数默认是8,阻塞队列容量默认是
Integer.MAX_VALUE
,可见默认的设置在生产环境使用时存在资源耗尽的风险。可通过配置文件调整(配置项对应类:org.springframework.boot.autoconfigure.task.TaskExecutionProperties)
如果AsyncConfigurer
提供了Executor
,则使用该Executor作为默认执行器,否则通过getDefaultExecutor
方法获取默认执行器
在AsyncExecutionInterceptor#getDefaultExecutor
方法中,首先从父类方法中获取执行器(从spring容器中获取org.springframework.core.task.TaskExecutor
类型的bean或者name是taskExecutor
的bean),若为空,则使用SimpleAsyncTaskExecutor
默认情况下,spring容器中并没有TaskExecutor类型的bean,但是在TaskExecutorConfiguration
(该配置类是由TaskExecutionAutoConfiguration自动配置类使用@Import导入)配置类中,向spring容器中注册了name是taskExecutor的bean
自定义异步执行器
自定义默认异步执行器
以下两种方式都是在自定义默认的异步执行器,也就说@Async不指定线程池时使用的默认异步执行器
- 自定义配置类,并实现
org.springframework.scheduling.annotation.AsyncConfigurer
接口,重写getAsyncExecutor
方法 - 向容器中注册TaskExecutor类型的bean,覆盖内置的TaskExecutor
自定义普通异步执行器
- 自定义普通异步执行器的bean名称,不可设置为taskExecutor,且类型不可以是TaskExecutor,否则会成为默认异步执行器
- 可创建org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor对象,并自定义其属性值,然后将该对象注册到spring容器中
异常处理
异步方法的异常捕获和处理
默认的异常处理器SimpleAsyncUncaughtExceptionHandler
示例
2024-09-20T15:59:20.776+08:00 ERROR 34764 --- [ task-1] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected exception occurred invoking async method: public void com.example.box.dynamicproxy.TestJdkProxyServiceImpl.run()
java.lang.RuntimeException: 公司又停发工资了!!!
at com.example.box.dynamicproxy.TestJdkProxyServiceImpl.run(TestJdkProxyServiceImpl.java:14) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
自定义异常处理器
配置类实现AsyncConfigurer接口的getAsyncUncaughtExceptionHandler()
方法,返回一个自定义的AsyncUncaughtExceptionHandler实现类的实例