Spring Boot中控制器@ExceptionHandler生效,@ControllerAdvice中的却不生效?
Spring Boot全局@ControllerAdvice异常处理器未生效问题排查与解决
问题场景
在Spring Boot MVC应用中,存在以下代码逻辑:
- 控制器
RegistrationController调用服务类InternalRegistrationService的confirmEmail方法,该方法会抛出TokenException及其子类TokenExpiredException - 控制器内部通过
@ExceptionHandler(TokenExpiredException.class)可以正常捕获TokenExpiredException异常 - 定义了标注
@ControllerAdvice的GlobalExceptionHandler,用于捕获除TokenExpiredException外的其他TokenException类型异常,但实际运行时该全局处理器未生效,未被捕获的异常直接返回500错误
相关代码如下:
控制器代码
@Controller @RequestMapping("/registration") public class RegistrationController { @GetMapping({"/email-confirmation"}) public String emailConfirmation(@RequestParam String token) { internalRegistrationService.confirmEmail(token); return "redirect:/"; } @ExceptionHandler(TokenExpiredException.class) public ModelAndView handleTokenExpiredException(Exception e) { ModelAndView mv = new ModelAndView(); // 异常处理逻辑 return mv; } }
服务类代码
@Service public class InternalRegistrationService { public void confirmEmail(String token) throws TokenException { emailTokenValidator.validate(token); } }
全局异常处理器代码
@ControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); @ExceptionHandler(TokenException.class) @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "out of cookies") public void handleTokenException(Exception e) { logger.debug("{}", e.getMessage(), e); } }
问题原因
经排查确认:全局异常处理器GlobalExceptionHandler未被Spring的类路径扫描机制纳入管理,导致Spring无法识别并注册该全局异常处理组件。
解决方法
可以通过以下几种方式确保Spring能够扫描到GlobalExceptionHandler:
调整包结构(推荐)
将GlobalExceptionHandler移动到Spring Boot主启动类所在的包或其子包下。Spring Boot默认会自动扫描主启动类所在包及其所有子包内的组件,无需额外配置。显式指定扫描包范围
在主启动类上添加@ComponentScan注解,指定包含GlobalExceptionHandler的包路径:@SpringBootApplication @ComponentScan(basePackages = {"com.yourproject.controller", "com.yourproject.exception"}) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }替换示例中的包路径为实际项目中对应的包。
直接指定要扫描的类
如果不想调整包结构或指定包路径,也可以直接在@ComponentScan中指定GlobalExceptionHandler类:@SpringBootApplication @ComponentScan(basePackageClasses = {RegistrationController.class, GlobalExceptionHandler.class}) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
验证效果
修改完成后,当抛出非TokenExpiredException的TokenException异常时,GlobalExceptionHandler的handleTokenException方法会被触发,接口会返回404 NOT FOUND状态码,而非之前的500错误。
内容的提问来源于stack exchange,提问作者Slevin
相关产品推荐
相关产品推荐

