복붙노트

[SPRING] Spring Async Uncaught Exception 핸들러

SPRING

Spring Async Uncaught Exception 핸들러

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

모든 비동기 메서드를 try catch하지 않고도 Spring Async 프레임 워크를 사용하여 어떻게 로그 할 수 있습니까? 보통처럼 DefaultUncaughtExceptionHandler에 전달하지 않는 것 같습니다.

해결법

  1. ==============================

    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. ==============================

    2.업데이트 : Spring 4.1부터

    업데이트 : Spring 4.1부터

    Spring 4.1부터 @Async void 메소드에 대해 AsyncUncaughtExceptionHandler를 사용할 수 있습니다.

    Spring Reference Doc, @Async로 예외 관리하기

    (이 기능은 DD가 impovement 요청을 제기 한 후에 소개되었습니다 : https://jira.spring.io/browse/SPR-8995,이 대답에 대한 설명 참조)

    봄 4.1 이전

    @Async 메서드를 반환하는 void 예외를 처리하는 방법이 누락 된 것처럼 보입니다. (참조 또는 java 문서에서 힌트를 찾을 수 없습니다.)

    솔루션에 대해 상상할 수있는 것 : AspectJ를 사용하여 예외를 기록하는 모든 @Async 메서드를 구현하는 일종의 래퍼를 작성해보십시오.

    로그 용어에 대해서는 스프링 버그 추적기에서 기능 요청을 작성하는 것이 좋습니다.

  3. ==============================

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

    참고 : 주사 가능한 예외 처리기는 옵션입니다. 모든 예외에 대해 새 인스턴스를 만들 수 있습니다. 스프링의 기본 범위가 싱글 톤이므로 모든 예외에 대해 새 인스턴스를 만들 필요가 없기 때문에 제 조언은 예외 처리기 클래스에 대한 주입을 사용합니다.

  4. from https://stackoverflow.com/questions/8735870/spring-async-uncaught-exception-handler by cc-by-sa and MIT license