简体   繁体   中英

Custom AsyncUncaughtExceptionHandler

Using the following configuration for @Async methods :

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        //Just to experiment
        return new SimpleAsyncTaskExecutor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }
}

Is there a way to "get" the ability to autowire (or similar) Services ?

I'd like to use such Services to record errors in database and use common services.

Non working sample :

@Component //seems pointless
public class CustomAsyncExceptionHandler extends ServiceCommons implements AsyncUncaughtExceptionHandler {
    protected Logger LOG = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private MyService myService; //always null

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
        //null pointer !
        myService.doSomething(throwable);
    }
}

When using not in @Async methods, @ControllerAdvice global exception handler allows @Autowired fields. Why not in this case ? Is this because of async thread management ?

I just faced this problem and solved this way:

@Configuration
@EnableAsync
public class MyAsyncConfigurer implements AsyncConfigurer {

    private CustomAsyncExceptionHandler customAsyncExceptionHandler;

    //...
    //other code here
    //...

    @Autowired
    public void setCustomAsyncExceptionHandler(CustomAsyncExceptionHandler customAsyncExceptionHandler) {
        this.customAsyncExceptionHandler = customAsyncExceptionHandler;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return this.customAsyncExceptionHandler;
    }
}

Custom async exception handler annotated with @Component:

@Component
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler     {

    private MyMailService myMailService;

    @Autowired
    public void setMyMailService(MyMailService myMailService) {
        this.myMailService= myMailService;
    }

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
        myMailService.sendMailToAdmin(throwable, method.getName());
    }
}

IoC injects both, myMailService and customAsyncExceptionHandler, correctly whith no errors.

I don't think my solution is the most elegant, but tell me what you think. the idea is to bypass the automatic injection mechanism by using ApplicationContextAware interface. My first attempt was to make my AsyncUncaughtExceptionHandler implementing class to also implement ACAware. But that didn't work. Somehow this class, even annotated as Component or Service seems to live a bit outside the Spring environment. So I did this:

@Configuration
@EnableAsync
public class DemoAsyncConfigurer implements AsyncConfigurer, ApplicationContextAware {

  private ApplicationContext applicationContext;

And in the same class:

@Override
  public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    DemoAsyncExceptionHandler demoHandler = new DemoAsyncExceptionHandler(); // you can't add the parameter in this constructor, for some reason...
    demoHandler.setApplicationContext(applicationContext);
    return demoHandler;
  }

  /**
   * 
   * {@inheritDoc}
   */
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }

My DemoAsyncExceptionHandler has the following:

private ApplicationContext applicationContext;

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;

  }

public void handleUncaughtException(Throwable throwable, Method method, Object... params) {
    UserService userService = this.applicationContext.getBean("userService", UserService.class);
    // call userService method

That worked! Hope I have helped

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM