BaseException 基础异常和 GlobalExceptionHandler 全局异常处理器执行流程

一、BaseException基础异常

  1. 设计定位

    • 继承RuntimeException,作为业务异常的基类
    • 通过枚举BasicEnum封装标准化错误码和消息
    public BaseException(BasicEnum basicEnum) {
        this.basicEnum = basicEnum; // 强制初始化错误类型
    }
  2. 触发场景

    • 业务逻辑中主动抛出(如参数校验失败、资源不存在等)
    if (param == null) {
        throw new BaseException(BasicEnum.PARAM_ERROR);
    }

二、GlobalExceptionHandler全局处理器


四、关键匹配规则

  1. 核心机制

    • 使用@RestControllerAdvice+@ExceptionHandler捕获所有控制器层异常
    • 优先级高于默认的Spring Boot错误处理
  2. 执行流程

    graph TD
    A[业务代码抛出BaseException] --> B[GlobalExceptionHandler拦截]
    B --> C{异常类型匹配?}
    C -->|BaseException| D[执行handleBaseException]
    C -->|其他异常| E[执行handleUnknownException]
    D --> F[记录日志并返回ResponseResult]
    E --> G[记录日志并返回500错误]
  3. 典型处理逻辑

    三、核心执行顺序

  4. BaseException的作用

    • 作为自定义业务异常的基类(继承RuntimeException),用于封装业务错误码(如BasicEnum
    • 业务代码主动抛出(如throw new BaseException(BasicEnum.PARAM_ERROR)
  5. GlobalExceptionHandler的作用

    • 通过@RestControllerAdvice注解声明为全局异常处理器
    • 通过@ExceptionHandler方法捕获并处理异常,返回统一响应格式
  6. 实际执行流程

    graph TD
    A[业务代码抛出BaseException] --> B{当前Controller是否有@ExceptionHandler?}
    B -->|是| C[优先执行Controller内匹配的异常处理]
    B -->|否| D[由GlobalExceptionHandler.handleBaseException处理]
  7. 精确优先原则

    • 若存在@ExceptionHandler(BaseException.class),则优先匹配该方法
    • 若不存在,则向上匹配父类异常处理器(如RuntimeExceptionException
  8. 全局处理器的兜底作用

    • 当Controller内部未处理异常时,GlobalExceptionHandler才会介入
    • 通过@Order注解可调整多个全局处理器的优先级
<think>嗯,用户问的是如何实现全局的自定义异常捕捉。首先,我需要确定用户的使用场景。可能他们正在开发一个Java Web应用,比如使用Spring Boot,或者是普通的Java应用?不同的框架有不同的处理方式,比如Spring有@ControllerAdvice,而普通的Java可能需要自定义异常处理器。 用户可能遇到的问题是没有统一的异常处理机制,导致每个地方都要try-catch,代码冗余,维护困难。他们希望有一个全局的解决方案,能够集中处理异常,返回统一的错误格式,或者记录日志,避免重复代码。 接下来,我需要考虑不同的技术栈下的实现方法。如果是Spring Boot的话,@ControllerAdvice结合@ExceptionHandler是最常用的方式,这样可以捕捉Controller层的异常。如果是普通Java应用,可能需要使用Thread的UncaughtExceptionHandler来捕捉未被捕获的异常。 另外,用户可能对AOP感兴趣,通过切面来拦截异常,但这种方式可能更适用于方法级别的统一处理,结合自定义注解。需要分情况讨论不同的实现方式,并给出示例代码。 还要考虑用户可能的错误,比如忘记在Spring中配置@EnableWebMvc,或者在普通Java中没有正确设置默认的异常处理器。需要提醒常见的错误注意事项,比如确保覆盖所有异常类型,避免吞掉异常导致问题难以排查。 最后,总结最佳实践,比如在Spring项目中使用@ControllerAdvice,普通应用使用UncaughtExceptionHandler,以及结合日志记录统一响应体。这样用户可以根据自己的项目类型选择合适的方案,提升代码的可维护性用户体验。</think>在Java中实现全局异常捕捉需要根据技术栈选择不同方案,以下分场景详解核心实现路径: --- ### 一、Spring Boot项目实现(推荐方案) 通过`@ControllerAdvice` + `@ExceptionHandler`实现控制器层统一拦截 ```java @ControllerAdvice public class GlobalExceptionHandler { // 自定义业务异常处理 @ExceptionHandler(BusinessException.class) @ResponseBody public ResponseEntity<ErrorResult> handleBusinessEx(BusinessException ex) { ErrorResult error = new ErrorResult(ex.getCode(), ex.getMessage()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); } // 兜底异常处理 @ExceptionHandler(Exception.class) @ResponseBody public ResponseEntity<ErrorResult> handleUnknownEx(Exception ex) { ErrorResult error = new ErrorResult(500, "系统繁忙,请稍后重试"); log.error("全局异常捕获: ", ex); // 使用SLF4J记录日志 return ResponseEntity.internalServerError().body(error); } } // 统一错误响应体 @Data @AllArgsConstructor class ErrorResult { private int code; private String msg; } ``` **生效条件**: 1. 确保Spring Boot启动类包含`@EnableWebMvc` 2. 自定义异常需继承`RuntimeException` ```java public class BusinessException extends RuntimeException { private int code; public BusinessException(int code, String message) { super(message); this.code = code; } } ``` --- ### 二、原生Java应用实现 通过`Thread.setDefaultUncaughtExceptionHandler`设置全局处理器 ```java public class GlobalExceptionConfig { public static void init() { Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { System.err.println("【全局异常捕获】线程 " + thread.getName() + " 崩溃:"); throwable.printStackTrace(); // 可扩展:发送报警邮件/写入错误日志文件 sendAlert(throwable); }); } private static void sendAlert(Throwable t) { // 实现邮件/短信报警逻辑 } } // 在main方法初始化 public class MainApp { public static void main(String[] args) { GlobalExceptionConfig.init(); // 其他业务代码... } } ``` --- ### 三、AOP增强方案(方法级拦截) 通过切面实现任意方法的异常监控 ```java @Aspect @Component public class ExceptionAspect { @AfterThrowing(pointcut = "execution(* com.yourpackage..*.*(..))", throwing = "ex") public void handleException(JoinPoint jp, Exception ex) { String method = jp.getSignature().toShortString(); System.out.printf("方法 %s 抛出异常: %s%n", method, ex.getMessage()); // 可在此进行异常转换/记录详细日志 if(ex instanceof SQLException) { throw new DatabaseException("数据库操作失败", ex); // 转换异常类型 } } } ``` --- ### 四、不同方案的对比选型 | 方案 | 适用场景 | 优势 | 局限性 | |--------------------|-------------------------|-----------------------------|---------------------| | Spring全局异常处理 | Web应用(Spring体系) | 与HTTP状态码深度整合 | 仅作用于Controller层 | | UncaughtException | 桌面应用/后台服务 | 捕捉所有线程崩溃 | 无法处理已try-catch的异常 | | AOP切面 | 需要方法级监控 | 细粒度控制 | 需要引入AOP依赖 | --- ### 五、最佳实践建议 1. **异常分级处理**(核心示例): ```java // 自定义异常体系 public abstract class BaseException extends RuntimeException { private ErrorType type; // 枚举定义错误类型 } public class AuthException extends BaseException { /* 权限异常 */ } public class ParamException extends BaseException { /* 参数异常 */ } ``` 2. **日志记录规范**: ```java @ExceptionHandler(Exception.class) public void handleEx(Exception ex) { log.error("错误上下文: {}", getCurrentRequestInfo()); log.error("异常堆栈: ", ex); // 必须打印完整堆栈 } ``` 3. **生产环境响应**: ```json // 开发环境返回详细错误 { "code":500, "msg":"NullPointer", "stackTrace":"..." } // 生产环境返回简化信息 { "code":500, "msg":"系统异常,请联系管理员" } ``` --- **常见错误避坑**: 1. 避免在全局处理器中直接`ex.printStackTrace()`(应采用日志框架) 2. 不要忘记在自定义异常中调用`super(message)`(保留异常链) 3. 谨慎使用`@ExceptionHandler(Throwable.class)`(会覆盖其他处理器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值