You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:17:34