@Override
@Async
public void asyncExceptionTest() {
int i=1/0;
}
如何在Spring Async框架中记录此内容,而无需在每个异步方法周围放置try catch?它似乎不会像正常情况下一样传递给DefaultUncaughtExceptionHandler
。
@Override
@Async
public void asyncExceptionTest() {
int i=1/0;
}
如何在Spring Async框架中记录此内容,而无需在每个异步方法周围放置try catch?它似乎不会像正常情况下一样传递给DefaultUncaughtExceptionHandler
。
@Async
方法可以配置自定义的Executor
来记录任何抛出的异常。
以下代码实现了这个模式。任何标有@Async
的方法都将使用由方法public Executor getAsyncExecutor()
返回的Executor
。这将返回HandlingExecutor
,它负责所有日志记录(在这种情况下,它只打印单词“CAUGHT!”,但您可以用日志替换它)。
@Configuration
@EnableAsync
public class ExampleConfig implements AsyncConfigurer {
@Bean
public Runnable testExec() {
return new TestExec();
}
@Override
public Executor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return new HandlingExecutor(executor);
}
}
public class HandlingExecutor implements AsyncTaskExecutor {
private AsyncTaskExecutor executor;
public HandlingExecutor(AsyncTaskExecutor executor) {
this.executor = executor;
}
@Override
public void execute(Runnable task) {
executor.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
executor.execute(createWrappedRunnable(task), startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
return executor.submit(createWrappedRunnable(task));
}
@Override
public <T> Future<T> submit(final Callable<T> task) {
return executor.submit(createCallable(task));
}
private <T> Callable<T> createCallable(final Callable<T> task) {
return new Callable<T>() {
@Override
public T call() throws Exception {
try {
return task.call();
} catch (Exception e) {
handle(e);
throw e;
}
}
};
}
private Runnable createWrappedRunnable(final Runnable task) {
return new Runnable() {
@Override
public void run() {
try {
task.run();
} catch (Exception e) {
handle(e);
}
}
};
}
private void handle(Exception e) {
System.out.println("CAUGHT!");
}
}
在Spring 4.1之前
看起来好像是一个缺失的功能,如何处理返回void
的@Async
方法的异常。(我在参考资料或Java文档中找不到任何提示)
我能想到的解决方案是:尝试使用AspectJ来编写一些包装器,将所有的@Async
方法包装起来,以记录异常。
对于长期来说,我建议在Spring的错误跟踪器中创建一个功能请求。
首先,您应该创建一个自定义异常处理程序类,如下所示:
@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(AsyncExceptionHandler.class);
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("Unexpected asynchronous exception at : "
+ method.getDeclaringClass().getName() + "." + method.getName(), ex);
}
}
接下来,您应该像以下方式在配置中设置自定义异常处理程序类;
@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
@Autowired
private AsyncExceptionHandler asyncExceptionHandler;
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler;
}
}
注意:可注入式异常处理程序是一种选择。您可以为每个异常创建一个新实例。我的建议是使用注入式异常处理程序类,因为Spring的默认作用域是单例,所以不需要为每个异常创建新实例。
您可以使用标准的Spring AOP方法
@Aspect
@Component
@Slf4j
public class AsyncHandler {
@Around("@annotation(org.springframework.scheduling.annotation.Async)")
private Object handle(ProceedingJoinPoint pjp) throws Throwable {
try {
Object retVal = pjp.proceed();
return retVal;
} catch (Throwable e) {
log.error("in ASYNC, method: " + pjp.getSignature().toLongString() + ", args: " + AppStringUtils.transformToWellFormattedJsonString(pjp.getArgs()) + ", exception: "+ e, e);
throw e;
}
}
}