我的Spring Boot(ver 1.4.2)应用程序中有很多计划任务,并希望使用一个处理程序来捕获它们的所有异常,就像对@ExceptionHandler注释的普通控制器一样。由于线程的原因,此方法不适用于使用@Scheduled注释定义的任务:
@Component
public class UpdateJob {
@Transactional
@Scheduled(cron = "0 1 0 * * *")
public void runUpdateUsers() {
userService.updateUsers();
}
@ExceptionHandler
public void handle(Exception e) {
// some more logic here
logger.error(e.getMessage());
}
}
@ExceptionHandler对@Scheduled方法不起作用(事实证明它并不意味着)。相反,Spring Boot使用它自己的LoggingErrorHandler:
2016-12-08 15:49:20.016 ERROR 23119 --- [pool-7-thread-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task.
我可以以某种方式替换或提供计划任务的默认异常处理程序吗?或者它是否有意义(并且可能)切换到PropagatingErrorHandler,据我所知,进一步传播错误?有没有其他方法可以仅使用Java配置(没有XML)来实现目标?
这不是this question的重复,因为它明确要求基于Java配置的解决方案,而不是XML (因此,在没有任何XML配置的情况下将其合并到Spring Boot项目中是不错的)。
还有一些答案演示了如何从头开始配置TaskScheduler。例如,此answer要求您还定义池大小,最大池大小,队列容量。 Here是一个解决方案,也需要非常广泛的配置。 Documentation显示了如何配置其他方面,但不显示如何指定错误处理。但是 Java配置所需的最小工作量是什么,这样我才能最大限度地保留Spring Boot默认值(线程池,执行器配置等)。
答案 0 :(得分:4)
如评论中所述,@ExceptionHandler
适用于Spring MVC控制器。
如果您想要为单个调度程序提供异常处理逻辑,最简单且最易于维护的是将其包装到try-catch块中并在那里处理错误。
如果要为各种调度程序应用相同的错误处理程序,请关注@M。 Deinum的建议。
答案 1 :(得分:2)
以下是设置自定义错误处理程序(Spring 2.0.2)的示例:
@Bean
public TaskScheduler taskScheduler() {
ConcurrentTaskScheduler scheduler = new ConcurrentTaskScheduler();
scheduler.setErrorHandler(throwable -> { /* custom handler */ });
return scheduler;
}
答案 2 :(得分:0)
我认为使用AOP可能会解决您的问题。
步骤
仅供参考: 我已经在单个方法上研究过AOP并捕获了它的异常并记录了下来,但就我个人而言,到目前为止,我还没有拿出您指定的用例。上面的解决方案只是一个建议。
@Aspect
@Component
public class UpdateJobAOP {
@Pointcut("execution(* com.foo.bar.UpdateJob.*(..))")
public void all() {}
@AfterThrowing(pointcut="all()", throwing="ex")
public void afterThrowing(Exception ex) {
// Do what you want
ex.printStackTrace();
}
}
答案 3 :(得分:0)
您在PropagatingErrorHandler
上走的是正确的路,但是您稍微误解了目的。这将导致异常继续在堆栈中继续传播,从而导致计划的任务将来不再运行。另外,它对TaskUtils
是私有的,因此您无法访问它。
您将需要实现自己的ErrorHandler
,但只能有一个处理程序。至少您要记录该异常,因为您将不再有Spring为您记录该异常。
假设您没有自己的自定义TaskScheduler
bean,要在Spring Boot中创建自己的ErrorHandler
,请在@Configuration类中实现org.springframework.boot.task.TaskSchedulerCustomizer
。
@Override
public void customize(ThreadPoolTaskScheduler taskScheduler) {
taskScheduler.setErrorHandler(new CustomErrorHandler());
}
private static class CustomErrorHandler implements ErrorHandler {
private static final Logger logger = LoggerFactory.getLogger(CustomErrorHandler.class);
@Override
public void handleError(Throwable t) {
logger.error("Scheduled task threw an exception: {}", t.getMessage(), t);
}
}
因为ErrorHandler
是@FunctionalInterface
,所以您可以这样做:
taskScheduler.setErrorHandler(t -> { /* Handle exception here */});
(基于Spring Boot 2.1.8)