Spring Async Uncaught Exception обработчик - PullRequest
23 голосов
/ 05 января 2012
@Override
@Async
public void asyncExceptionTest() {
    int i=1/0;
}

Как я могу записать это, используя Spring Async Framework, не пытаясь поймать каждый метод async?Кажется, он не переходит на DefaultUncaughtExceptionHandler как обычно.

Ответы [ 3 ]

19 голосов
/ 28 января 2012
@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!");
    }
}
16 голосов
/ 05 января 2012

Обновление: С весны 4.1

Начиная с весны 4.1 Возможно иметь AsyncUncaughtExceptionHandler для @Async void методов.

Spring Reference Doc, Глава 34.4.5 Управление исключениями с помощью @ Async

... Однако для типа возврата void исключение не обрабатывается и не может быть передано. Для этих случаев может быть предоставлен AsyncUncaughtExceptionHandler для обработки таких исключений.

По умолчанию исключение просто регистрируется. Пользовательский AsyncUncaughtExceptionHandler может быть определен с помощью AsyncConfigurer или элемента XML на основе аннотации, управляемой заданием:

(Эта функция была введена после того, как DD поднял запрос на улучшение: https://jira.spring.io/browse/SPR-8995, см. Комментарии к этому ответу)


до весны 4.1

Похоже, отсутствует функция обработки исключений void, возвращающих @Async Метод. (Я не могу найти ни намека на ссылку или документ Java)

Что я могу себе представить для решения: попробуйте использовать AspectJ для написания какой-то обертки вокруг всех @Async методов, которые регистрируют исключения.

В качестве логарифмического слова я бы порекомендовал создать запрос о существе в средстве отслеживания ошибок.

7 голосов
/ 20 октября 2017

Прежде всего, вы должны создать класс обработчика исключений, подобный следующему;

@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;
    }

}

Примечание. Опциональный обработчик исключений - это опция. Вы можете создать новый экземпляр для каждого исключения. Мой совет - использовать Injection для класса обработчика исключений, потому что область действия Spring по умолчанию - singleton, поэтому нет необходимости создавать новый экземпляр для каждого исключения.

...