SpringBoot异步方法捕捉异常详解
本文实例为大家分享了SpringBoot异步方法捕捉异常的具体代码,供大家参考,具体内容如下
由于项目中定时器都采用异步执行方式
需要定时监控异步方法执行进度,异常情况
1执行进度
可以设置是否在执行,内存中添加执行标识即可。
防止多次执行可以通过拦截器对此,标识来判断,防止多次执行定时器
2异常捕捉
监控异步方法执行是否异常。
1无返回值
配置AsyncExceptionConfig类,统一处理。
定义异常捕获配置类AsyncExceptionConfig,配置类里面定义SpringAsyncExceptionHandler方法实现AsyncUncaughtExceptionHandler接口。
代码如下:
packagecn.bwjf.config; importcn.bwjf.common.constant.InitServiceIdEnum; importcn.bwjf.common.tools.InitServiceUtil; importlombok.extern.slf4j.Slf4j; importorg.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; importorg.springframework.context.annotation.Configuration; importorg.springframework.scheduling.annotation.AsyncConfigurer; /** *@description:异常捕获配置类 *@author:tizzy
*@version:1.0 *@date2019/9/21 */ @Configuration @Slf4j publicclassAsyncExceptionConfigimplementsAsyncConfigurer{ /** *@description:设置异步方法线程参数 *@author:tizzy *@version:1.0 */ @Bean @Override publicExecutorgetAsyncExecutor(){ ThreadPoolTaskExecutorexecutor=newThreadPoolTaskExecutor(); //根据自己机器配置 executor.setCorePoolSize(8); executor.setMaxPoolSize(16); executor.setQueueCapacity(64); executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy()); executor.setThreadNamePrefix("SpringAsyncThread-"); returnexecutor; } @Override publicAsyncUncaughtExceptionHandlergetAsyncUncaughtExceptionHandler(){ returnnewSpringAsyncExceptionHandler(); } classSpringAsyncExceptionHandlerimplementsAsyncUncaughtExceptionHandler{ @Override publicvoidhandleUncaughtException(Throwablethrowable,Methodmethod,Object...objects){ log.info("------我是Async无返回方法的异常处理方法---------"); //通过反射获取各个初始化方法名字 StringmethodName=method.getName(); log.info("当前异常方法名=={}",methodName); //根据方法名字记录异常略。。。。 log.info("------我是Async无返回方法的异常处理方法---------"); } } }
2有返回值
返回值用AsyncResult包装返回
AsyncResult是Future接口的子类,所以也可以通过future.get()获取返回值的时候捕获ExcecutionException。
@Async publicFutureasyncMethod(){ try{ Thread.sleep(5000); returnnewAsyncResult ("helloworld!!!!"); }catch(InterruptedExceptione){ // } returnnull; }
调用
try{ Futurefuture=service.asyncMethod(); future.get(); }catch(ExecutionExceptione){ logger.error("exceptionoccurs",e); }catch(InterruptedExceptione){ logger.error("exceptionoccurs",e); }
什么是Future类型?
Future是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果的接口。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
它的接口定义如下:
publicinterfaceFuture{ booleancancel(booleanmayInterruptIfRunning); booleanisCancelled(); booleanisDone(); Vget()throwsInterruptedException,ExecutionException; Vget(longtimeout,TimeUnitunit) throwsInterruptedException,ExecutionException,TimeoutException; }
它声明这样的五个方法:
cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回true。
isDone方法表示任务是否已经完成,若任务完成,则返回true;
get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
get(longtimeout,TimeUnitunit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
也就是说Future提供了三种功能:
判断任务是否完成;
能够中断任务;
能够获取任务执行结果。
3异步方法中事务
@Async调用中的事务处理机制
在@Async标注的方法,同时也适用了@Transactional进行了标注;在其调用数据库操作之时,将无法产生事务管理的控制,原因就在于其是基于异步处理的操作。
正确做法
如何给这些操作添加事务管理呢?可以将需要事务管理操作的方法放置到异步方法内部,在内部被调用的方法上添加@Transactional.
例如:
方法A,使用了@Async/@Transactional来标注,但是无法产生事务控制的目的。
方法B,使用了@Async来标注, B中调用了C、D,C/D分别使用@Transactional做了标注,是可以实现事务控制的目的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。