Spring Обработчик исключений Async Uncaught
@Override
@Async
public void asyncExceptionTest() {
int i=1/0;
}
Как я могу зарегистрировать это с помощью Spring инфраструктуры Async без необходимости ставить try catch вокруг каждого метода async? Кажется, что он не соответствует стандарту DefaultUncaughtExceptionHandler
.
Ответы
Ответ 1
@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
Обновление: Поскольку Spring 4.1
Так как Spring 4.1 Возможно AsyncUncaughtExceptionHandler для методов @Async
void
.
Spring Ссылка Doc, Глава 34.4.5 Управление исключениями с @Async
... Однако с типом возврата void исключение не отображается и не может быть передано. В этих случаях для обработки таких исключений может быть предоставлен AsyncUncaughtExceptionHandler.
По умолчанию исключение просто регистрируется. Пользовательский AsyncUncaughtExceptionHandler может быть определен с помощью AsyncConfigurer или задачи: XML-элемент, управляемый аннотацией.
(Эта функция была введена после того, как DD поднял запрос на перемещение: https://jira.spring.io/browse/SPR-8995, см. комментарии к этому ответу)
До Spring 4.1
Похоже на недостающую функцию, как обрабатывать исключения void
возвращающего метода @Async
. (Я не могу найти никакого намека на ссылку или java doc)
Что я могу себе представить из решения: попробуйте использовать AspectJ для написания какой-то обертки arround всех @Async
методов, которые регистрируют исключения.
Для термина журнала я бы рекомендовал создать запрос на защиту в Spring отслеживании ошибок.
Ответ 3
Прежде всего, вы должны создать собственный класс обработчика исключений, например:
@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, поэтому нет необходимости создавать новый экземпляр для каждого исключения.