run example async java spring asynchronous exception-handling uncaughtexceptionhandler

java - example - spring boot run async



Spring Async Uncaught Exception handler (3)

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

¿Cómo puedo registrar esto utilizando Spring Async framework sin tener que poner try catch en todos los métodos asíncronos? No parece pasar a la DefaultUncaughtExceptionHandler como normal.


Actualización: Desde la primavera 4.1

Desde la primavera 4.1 es posible tener un AsyncUncaughtExceptionHandler para los métodos de @Async void .

Spring Reference Doc, Capítulo 34.4.5 Gestión de excepciones con @Async

... Sin embargo, con un tipo de retorno nulo, la excepción no se captura y no se puede transmitir. Para esos casos, se puede proporcionar un AsyncUncaughtExceptionHandler para manejar dichas excepciones.

Por defecto, la excepción simplemente se registra. Un AsyncUncaughtExceptionHandler personalizado se puede definir a través de AsyncConfigurer o la tarea: elemento XML controlado por anotación.

(Esta función se introdujo después de que DD presentó una solicitud de mejora: https://jira.spring.io/browse/SPR-8995 , vea los comentarios de esta respuesta)

Antes de la primavera 4.1

Parece una característica que falta en cómo manejar las excepciones de un void devuelve el método @Async . (No puedo encontrar ninguna pista en la referencia o en el documento de Java)

Lo que puedo imaginar de una solución: intente usar AspectJ para escribir algún tipo de envoltorio @Async todos los métodos @Async que registran las excepciones.

Para el término de registro, recomendaría crear una solicitud de freature en el rastreador de errores de Spring.


En primer lugar, debe crear una clase de controlador de excepciones personalizada como la siguiente;

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

Después de eso, debe configurar su clase de controlador de excepciones personalizada en su configuración como sigue:

@Configuration @EnableAsync public class AsyncConfig extends AsyncConfigurerSupport { @Autowired private AsyncExceptionHandler asyncExceptionHandler; @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return asyncExceptionHandler; } }

Nota: el controlador de excepciones inyectables es una opción. Puede crear una nueva instancia para cada excepción. Mi consejo es usar Injection para la clase de controlador de excepciones, ya que el alcance predeterminado de spring es singleton, por lo que no es necesario crear una nueva instancia para cada excepción.


@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!"); } }