弹簧异步未捕获异常处理程序

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

如何使用Spring Async框架记录此内容,而不必在每个异步方法周围放置 try catch?它似乎没有像正常人一样。DefaultUncaughtExceptionHandler


答案 1

@Async可以使用自定义方法配置方法,以记录任何引发的异常。Executor

下面的代码实现此模式。任何标记的方法都将使用由方法 返回的 。这将返回 what 负责所有日志记录(在本例中,它只打印单词“CATCH!”,但您可以替换为日志记录。@AsyncExecutorpublic 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!");
    }
}

答案 2

更新:自春季4.1起

从Spring 4.1开始,可以有一个AsyncUncaughtExceptionHandler来获取方法。@Asyncvoid

春季参考文档,第 34.4.5 章 @Async异常管理

...但是,对于 void 返回类型,异常是未捕获的,无法传输。对于这些情况,可以提供 AsyncUncaughtExceptionHandler 来处理此类异常。

默认情况下,仅记录异常。自定义的 AsyncUncaughtExceptionHandler 可以通过 AsyncConfigurer 或 task:annotation-driven XML 元素来定义。

(此功能是在 DD 提出改进请求后引入的:https://jira.spring.io/browse/SPR-8995,请参阅此答案的评论)


春之前 4.1

看起来像如何处理返回方法的异常的缺失功能。(我在参考文献或java文档中找不到任何提示)void@Async

我能想象到的解决方案:尝试使用AspectJ编写某种包装器,围绕所有记录异常的方法。@Async

对于日志术语,我建议在弹簧错误跟踪器中创建一个 freature 请求。


推荐