@Override
@Async
public void asyncExceptionTest() {
int i=1/0;
}
すべての非同期メソッドにtrycatchを配置せずに、Spring Asyncフレームワークを使用してこれをログに記録するにはどうすればよいですか?DefaultUncaughtExceptionHandler
普通のようには伝わらないようです。
@Override
@Async
public void asyncExceptionTest() {
int i=1/0;
}
すべての非同期メソッドにtrycatchを配置せずに、Spring Asyncフレームワークを使用してこれをログに記録するにはどうすればよいですか?DefaultUncaughtExceptionHandler
普通のようには伝わらないようです。
@Async
メソッドはExecutor
、スローされた例外をログに記録するようにカスタムで構成できます。
次のコードは、このパターンを実装しています。でタグ付けされたメソッドはすべて、メソッドによって返されたもの@Async
を使用します。これにより、すべてのロギングを処理するが返されます(この場合、「CAUGHT!」という単語が出力されますが、ロギングに置き換えることができます。Executor
public Executor getAsyncExecutor()
HandlingExecutor
@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!");
}
}
更新:Spring4.1以降
Spring 4.1以降、メソッドにAsyncUncaughtExceptionHandlerを設定することができ@Async
void
ます。
Spring Reference Doc、第34.4.5章@Asyncによる例外管理
...ただし、voidリターンタイプでは、例外はキャッチされず、送信できません。そのような場合、そのような例外を処理するためにAsyncUncaughtExceptionHandlerを提供できます。
デフォルトでは、例外は単にログに記録されます。カスタムAsyncUncaughtExceptionHandlerは、AsyncConfigurerまたはtask:annotation-drivenXML要素を介して定義できます。
(この機能は、DDが不正行為のリクエストを出した後に導入されました: https://jira.spring.io/browse/SPR-8995 、この回答のコメントを参照してください)
春4.1以前
void
返されるメソッドの例外を処理する方法が欠落しているように見え@Async
ます。(リファレンスまたはjava docにヒントが見つかりません)
@Async
解決策について私が想像できること:AspectJを使用して、例外をログに記録するすべてのメソッドの周りにある種のラッパーを記述してみてください。
ログ用語については、春のバグトラッカーでフリーチュアリクエストを作成することをお勧めします。
まず、次のようなカスタム例外ハンドラークラスを作成する必要があります。
@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のデフォルトスコープはシングルトンであり、例外ごとに新しいインスタンスを作成する必要がないため、私のアドバイスは例外ハンドラークラスにインジェクションを使用することです。
標準のSpringAOPアプローチを使用できます
@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;
}
}
}