spring Boot项目怎么处理全局异常

发布时间:2021-09-09 11:48:44 作者:chen
来源:亿速云 阅读:221
# Spring Boot项目怎么处理全局异常

## 目录
1. [引言](#引言)
2. [为什么需要全局异常处理](#为什么需要全局异常处理)
3. [Spring Boot异常处理机制](#spring-boot异常处理机制)
4. [实现全局异常处理的5种方式](#实现全局异常处理的5种方式)
   - [4.1 @ControllerAdvice + @ExceptionHandler](#41-controlleradvice--exceptionhandler)
   - [4.2 实现ErrorController接口](#42-实现errorcontroller接口)
   - [4.3 @ResponseStatus自定义异常](#43-responsestatus自定义异常)
   - [4.4 HandlerExceptionResolver](#44-handlerexceptionresolver)
   - [4.5 Filter异常处理](#45-filter异常处理)
5. [最佳实践与进阶技巧](#最佳实践与进阶技巧)
6. [常见问题解决方案](#常见问题解决方案)
7. [总结](#总结)

## 引言

在Web应用开发中,异常处理是保证系统健壮性和用户体验的关键环节。Spring Boot作为流行的Java框架,提供了多种灵活的全局异常处理机制。本文将深入探讨5种核心实现方案,并通过完整代码示例展示如何构建企业级异常处理体系。

## 为什么需要全局异常处理

传统的try-catch方式存在以下问题:
- **代码重复**:每个Controller都需要重复异常处理逻辑
- **维护困难**:异常逻辑分散难以统一管理
- **响应不规范**:错误响应格式不一致
- **安全隐患**:可能暴露堆栈信息

全局异常处理的优势:
```java
// 传统方式 vs 全局处理
@GetMapping("/old")
public String oldMethod() {
    try {
        // 业务逻辑
    } catch (Exception e) {
        // 每个方法都要重复处理
        return "error";
    }
}

// 全局处理方式
@GetMapping("/new")
public String newMethod() {
    // 只需关注业务逻辑
    throw new BusinessException("操作失败");
}

Spring Boot异常处理机制

Spring Boot异常处理流程: 1. 请求进入Controller 2. 发生异常时查找@ExceptionHandler 3. 未处理则交给HandlerExceptionResolver 4. 最后进入BasicErrorController

sequenceDiagram
    participant Client
    participant Controller
    participant ExceptionHandler
    participant ErrorController
    
    Client->>Controller: HTTP Request
    Controller->>ExceptionHandler: 抛出异常
    alt 有匹配的@ExceptionHandler
        ExceptionHandler-->>Client: 自定义响应
    else 无匹配处理器
        Controller->>ErrorController: 转交处理
        ErrorController-->>Client: 默认错误页
    end

实现全局异常处理的5种方式

4.1 @ControllerAdvice + @ExceptionHandler

最推荐的解决方案

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        log.error("业务异常: {}", e.getMessage());
        return Result.fail(e.getCode(), e.getMessage());
    }
    
    // 处理系统异常
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        log.error("系统异常: ", e);
        return Result.fail(500, "系统繁忙");
    }
    
    // 处理验证异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleValidException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult()
                        .getFieldError()
                        .getDefaultMessage();
        return Result.fail(400, message);
    }
}

进阶配置

// 自定义注解实现异常分类处理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExceptionAdvice {}

// 按包路径指定处理范围
@ControllerAdvice(annotations = ExceptionAdvice.class)
public class AnnotationExceptionHandler {...}

// 响应状态码自动设置
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResponse handleIllegalArgument(...) {...}

4.2 实现ErrorController接口

适用于处理未被捕获的异常:

@RestController
public class CustomErrorController implements ErrorController {
    
    private final ErrorAttributes errorAttributes;
    
    public CustomErrorController(ErrorAttributes errorAttributes) {
        this.errorAttributes = errorAttributes;
    }
    
    @RequestMapping("/error")
    public Result<?> handleError(HttpServletRequest request) {
        Map<String, Object> attributes = errorAttributes
            .getErrorAttributes(new ServletWebRequest(request), 
                ErrorAttributeOptions.defaults());
        
        return Result.fail(
            (int)attributes.get("status"),
            (String)attributes.get("message")
        );
    }
}

4.3 @ResponseStatus自定义异常

定义层次化异常体系:

// 基础异常类
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class BaseException extends RuntimeException {
    private final int code;
    
    public BaseException(int code, String message) {
        super(message);
        this.code = code;
    }
}

// 具体业务异常
public class OrderNotFoundException extends BaseException {
    public OrderNotFoundException() {
        super(404001, "订单不存在");
    }
}

// 使用示例
@GetMapping("/order/{id}")
public Order getOrder(@PathVariable Long id) {
    return orderRepo.findById(id)
            .orElseThrow(OrderNotFoundException::new);
}

4.4 HandlerExceptionResolver

底层处理方案:

@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {
    
    @Override
    public ModelAndView resolveException(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler,
            Exception ex) {
        
        if (ex instanceof AuthenticationException) {
            return handleAuthException((AuthenticationException)ex, response);
        }
        return null; // 返回null继续后续处理
    }
    
    private ModelAndView handleAuthException(...) {
        response.setStatus(401);
        response.setContentType("application/json");
        // 写入JSON响应
        return new ModelAndView(); // 空视图表示已处理
    }
}

4.5 Filter异常处理

处理过滤器链中的异常:

@Component
public class ExceptionHandlingFilter extends OncePerRequestFilter {
    
    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain) throws ServletException, IOException {
        
        try {
            filterChain.doFilter(request, response);
        } catch (BusinessException e) {
            ErrorResponse error = new ErrorResponse(e.getCode(), e.getMessage());
            response.setStatus(400);
            response.getWriter().write(JsonUtils.toJson(error));
        } catch (Exception e) {
            // 处理其他异常
        }
    }
}

最佳实践与进阶技巧

异常日志记录规范

@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e, HttpServletRequest request) {
    log.error("""
        [全局异常] 请求路径: {} | 方法: {} | 参数: {} | 异常类型: {} 
        异常信息: {} | 堆栈: {}
        """, 
        request.getRequestURI(),
        request.getMethod(),
        request.getQueryString(),
        e.getClass().getName(),
        e.getMessage(),
        ExceptionUtils.getStackTrace(e));
    // ...
}

国际化异常消息

# messages.properties
error.order.notFound=订单不存在,ID: {0}
error.auth.denied=无访问权限
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @Autowired
    private MessageSource messageSource;
    
    @ExceptionHandler(OrderNotFoundException.class)
    public Result<?> handleOrderNotFound(
            OrderNotFoundException e, 
            HttpServletRequest request) {
        
        String message = messageSource.getMessage(
            "error.order.notFound",
            new Object[]{e.getOrderId()},
            request.getLocale());
        
        return Result.fail(404, message);
    }
}

性能监控集成

@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e, MeterRegistry registry) {
    registry.counter("system.exception", 
            "type", e.getClass().getSimpleName())
        .increment();
    // ...
}

常见问题解决方案

问题1:异常处理顺序冲突

解决方案:通过@Order注解指定优先级

@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
public class HighPriorityExceptionHandler {...}

问题2:404处理不生效

解决方案:配置ErrorController或添加兜底路由

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/notFound")
                .setViewName("forward:/error/404");
    }
}

问题3:异步请求异常处理

解决方案:配置AsyncUncaughtExceptionHandler

@Configuration
public class AsyncConfig implements AsyncConfigurer {
    
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }
}

总结

本文详细介绍了Spring Boot中5种全局异常处理方案,实际项目中推荐组合使用:

  1. 核心业务异常:@ControllerAdvice + 自定义异常体系
  2. 未捕获异常:ErrorController兜底处理
  3. 特殊场景:HandlerExceptionResolver补充处理
  4. 过滤器异常:ExceptionHandlingFilter专门处理

完整示例项目结构:

src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           ├── exception/      # 异常定义
│   │           ├── config/         # 异常配置
│   │           ├── handler/        # 处理器实现
│   │           └── Application.java
│   └── resources/
│       ├── messages/              # 国际化资源
│       └── application.yml

通过合理的异常处理设计,可以显著提升系统的: - 可维护性(集中管理) - 健壮性(兜底处理) - 用户体验(友好提示) - 可观测性(完善日志)

最佳实践建议:建立完整的异常分类体系,结合监控告警系统,实现从异常发生到修复的完整闭环。 “`

推荐阅读:
  1. Spring Boot 最流行的 16 条实践解读!
  2. 总结Spring异常处理

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring

上一篇:正则速记法的技巧有哪些

下一篇:怎么通过重启路由的方法切换IP地址

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》