28
@Override
@Async
public void asyncExceptionTest() {
    int i=1/0;
}

すべての非同期メソッドにtrycatchを配置せずに、Spring Asyncフレームワークを使用してこれをログに記録するにはどうすればよいですか?DefaultUncaughtExceptionHandler普通のようには伝わらないようです。

4

4 に答える 4

24

@AsyncメソッドはExecutor、スローされた例外をログに記録するようにカスタムで構成できます。

次のコードは、このパターンを実装しています。でタグ付けされたメソッドはすべて、メソッドによって返されたもの@Asyncを使用します。これにより、すべてのロギングを処理するが返されます(この場合、「CAUGHT!」という単語が出力されますが、ロギングに置き換えることができます。Executorpublic 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!");
    }
}
于 2012-01-28T13:57:05.263 に答える
21

更新: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を使用して、例外をログに記録するすべてのメソッドの周りにある種のラッパーを記述してみてください。

ログ用語については、春のバグトラッカーでフリーチュアリクエストを作成することをお勧めします。

于 2012-01-05T08:35:30.783 に答える
18

まず、次のようなカスタム例外ハンドラークラスを作成する必要があります。

@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のデフォルトスコープはシングルトンであり、例外ごとに新しいインスタンスを作成する必要がないため、私のアドバイスは例外ハンドラークラスにインジェクションを使用することです。

于 2017-10-20T13:57:22.227 に答える
2

標準の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;
       }
   }

}
于 2019-11-14T12:57:17.180 に答える