Spring Boot异常处理终极指南:自定义异常、全局异常捕获与优雅降级实战

DirtyJulia
DirtyJulia 2026-01-26T06:08:01+08:00
0 0 1

在现代Java微服务架构中,异常处理是构建健壮应用系统的关键环节。Spring Boot作为主流的微服务开发框架,提供了丰富的异常处理机制。本文将深入解析Spring Boot中的异常处理机制,从基础概念到高级实践,帮助开发者构建完善的异常处理体系。

一、Spring Boot异常处理基础概念

1.1 异常处理的重要性

在微服务架构中,异常处理不仅仅是代码的健壮性保障,更是用户体验和系统稳定性的关键。良好的异常处理机制能够:

  • 提供清晰的错误信息给客户端
  • 记录详细的错误日志便于问题排查
  • 实现优雅降级,提升系统可用性
  • 统一错误响应格式,便于前端处理

1.2 Spring Boot中的异常处理机制

Spring Boot通过多种机制实现异常处理:

  • @ControllerAdvice:全局异常处理器
  • @ExceptionHandler:方法级别的异常处理
  • @ResponseStatus:设置HTTP状态码
  • ErrorController:自定义错误页面

二、自定义异常类设计

2.1 自定义异常类的重要性

在实际开发中,我们不应该直接抛出系统内置的异常,而应该创建业务相关的自定义异常。这样做的好处包括:

  • 提供更清晰的业务语义
  • 便于区分不同类型的错误
  • 支持统一的错误码管理
  • 有利于异常处理逻辑的复用

2.2 自定义异常类设计模式

/**
 * 基础业务异常类
 */
public class BusinessException extends RuntimeException {
    private String code;
    private Object[] args;
    
    public BusinessException(String code, String message) {
        super(message);
        this.code = code;
    }
    
    public BusinessException(String code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }
    
    public BusinessException(String code, String message, Object... args) {
        super(message);
        this.code = code;
        this.args = args;
    }
    
    // getter和setter方法
    public String getCode() {
        return code;
    }
    
    public void setCode(String code) {
        this.code = code;
    }
    
    public Object[] getArgs() {
        return args;
    }
    
    public void setArgs(Object[] args) {
        this.args = args;
    }
}

/**
 * 参数验证异常
 */
public class ValidationException extends BusinessException {
    public ValidationException(String message) {
        super("VALIDATION_ERROR", message);
    }
    
    public ValidationException(String code, String message) {
        super(code, message);
    }
}

/**
 * 资源未找到异常
 */
public class ResourceNotFoundException extends BusinessException {
    public ResourceNotFoundException(String message) {
        super("RESOURCE_NOT_FOUND", message);
    }
    
    public ResourceNotFoundException(String resourceType, Long id) {
        super("RESOURCE_NOT_FOUND", 
              String.format("%s with id %d not found", resourceType, id));
    }
}

/**
 * 权限异常
 */
public class AccessDeniedException extends BusinessException {
    public AccessDeniedException(String message) {
        super("ACCESS_DENIED", message);
    }
}

2.3 异常码管理策略

/**
 * 错误码枚举类
 */
public enum ErrorCode {
    // 通用错误码
    SUCCESS(0, "操作成功"),
    INTERNAL_ERROR(500, "服务器内部错误"),
    VALIDATION_ERROR(400, "参数验证失败"),
    RESOURCE_NOT_FOUND(404, "资源未找到"),
    ACCESS_DENIED(403, "权限不足"),
    
    // 业务错误码
    USER_EXISTS(1001, "用户已存在"),
    USER_NOT_FOUND(1002, "用户不存在"),
    PASSWORD_ERROR(1003, "密码错误"),
    TOKEN_EXPIRED(1004, "token已过期"),
    TOKEN_INVALID(1005, "token无效");
    
    private final int code;
    private final String message;
    
    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
    
    public int getCode() {
        return code;
    }
    
    public String getMessage() {
        return message;
    }
}

/**
 * 基础异常响应类
 */
public class ErrorResponse {
    private int code;
    private String message;
    private String timestamp;
    private String path;
    
    public ErrorResponse(int code, String message) {
        this.code = code;
        this.message = message;
        this.timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }
    
    // getter和setter方法
    public int getCode() { return code; }
    public void setCode(int code) { this.code = code; }
    
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    
    public String getTimestamp() { return timestamp; }
    public void setTimestamp(String timestamp) { this.timestamp = timestamp; }
    
    public String getPath() { return path; }
    public void setPath(String path) { this.path = path; }
}

三、@ControllerAdvice全局异常捕获

3.1 @ControllerAdvice核心概念

@ControllerAdvice是Spring MVC提供的全局异常处理器注解,它能够拦截所有Controller中的异常,并统一处理。使用@ControllerAdvice可以避免在每个Controller中重复编写异常处理代码。

3.2 基础全局异常处理器实现

/**
 * 全局异常处理器
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    
    /**
     * 处理自定义业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex, WebRequest request) {
        log.error("Business exception occurred: {}", ex.getMessage(), ex);
        
        ErrorResponse errorResponse = new ErrorResponse(
            Integer.parseInt(ex.getCode()), 
            ex.getMessage()
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }
    
    /**
     * 处理参数验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(
            MethodArgumentNotValidException ex, WebRequest request) {
        log.error("Validation exception occurred: {}", ex.getMessage());
        
        StringBuilder errorMsg = new StringBuilder();
        ex.getBindingResult().getFieldErrors().forEach(error -> 
            errorMsg.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; ")
        );
        
        ErrorResponse errorResponse = new ErrorResponse(
            ErrorCode.VALIDATION_ERROR.getCode(),
            errorMsg.toString()
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }
    
    /**
     * 处理请求参数类型转换异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<ErrorResponse> handleTypeMismatchException(
            MethodArgumentTypeMismatchException ex, WebRequest request) {
        log.error("Type mismatch exception occurred: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            ErrorCode.VALIDATION_ERROR.getCode(),
            String.format("Parameter '%s' should be of type %s", 
                         ex.getName(), ex.getRequiredType().getSimpleName())
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }
    
    /**
     * 处理资源未找到异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFoundException(
            NoHandlerFoundException ex, WebRequest request) {
        log.error("Resource not found exception occurred: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            ErrorCode.RESOURCE_NOT_FOUND.getCode(),
            "Requested resource not found"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
    }
    
    /**
     * 处理全局异常
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex, WebRequest request) {
        log.error("Global exception occurred: {}", ex.getMessage(), ex);
        
        ErrorResponse errorResponse = new ErrorResponse(
            ErrorCode.INTERNAL_ERROR.getCode(),
            "Internal server error occurred"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
    }
    
    /**
     * 获取请求路径
     */
    private String getRequestPath(WebRequest request) {
        if (request instanceof ServletWebRequest) {
            return ((ServletWebRequest) request).getRequest().getRequestURI();
        }
        return "";
    }
}

3.3 高级异常处理器实现

/**
 * 增强版全局异常处理器
 */
@ControllerAdvice
@Slf4j
public class EnhancedGlobalExceptionHandler {
    
    /**
     * 处理Spring Security权限异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<ErrorResponse> handleAccessDeniedException(
            AccessDeniedException ex, WebRequest request) {
        log.warn("Access denied: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            ErrorCode.ACCESS_DENIED.getCode(),
            "Access denied"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(errorResponse);
    }
    
    /**
     * 处理认证异常
     */
    @ExceptionHandler(AuthenticationException.class)
    public ResponseEntity<ErrorResponse> handleAuthenticationException(
            AuthenticationException ex, WebRequest request) {
        log.warn("Authentication failed: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            401,
            "Authentication required"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(errorResponse);
    }
    
    /**
     * 处理HTTP状态码异常
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<ErrorResponse> handleMethodNotAllowedException(
            HttpRequestMethodNotSupportedException ex, WebRequest request) {
        log.warn("Method not allowed: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            405,
            String.format("Method %s not allowed", ex.getMethod())
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).body(errorResponse);
    }
    
    /**
     * 处理HTTP消息转换异常
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseEntity<ErrorResponse> handleHttpMessageNotReadable(
            HttpMessageNotReadableException ex, WebRequest request) {
        log.error("Http message not readable: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            ErrorCode.VALIDATION_ERROR.getCode(),
            "Invalid request body format"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }
    
    /**
     * 处理请求超时异常
     */
    @ExceptionHandler(TimeoutException.class)
    public ResponseEntity<ErrorResponse> handleTimeoutException(
            TimeoutException ex, WebRequest request) {
        log.error("Request timeout: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            408,
            "Request timeout"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body(errorResponse);
    }
    
    /**
     * 处理服务降级异常
     */
    @ExceptionHandler(FeignException.class)
    public ResponseEntity<ErrorResponse> handleFeignException(
            FeignException ex, WebRequest request) {
        log.error("Feign client error: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            ex.status(),
            "Service unavailable"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(ex.status()).body(errorResponse);
    }
    
    /**
     * 处理重复请求异常
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public ResponseEntity<ErrorResponse> handleDuplicateKeyException(
            DuplicateKeyException ex, WebRequest request) {
        log.error("Duplicate key exception: {}", ex.getMessage());
        
        ErrorResponse errorResponse = new ErrorResponse(
            409,
            "Resource already exists"
        );
        errorResponse.setPath(getRequestPath(request));
        
        return ResponseEntity.status(HttpStatus.CONFLICT).body(errorResponse);
    }
    
    private String getRequestPath(WebRequest request) {
        if (request instanceof ServletWebRequest) {
            HttpServletRequest httpRequest = ((ServletWebRequest) request).getRequest();
            return httpRequest.getRequestURI();
        }
        return "";
    }
}

四、微服务场景下的异常处理

4.1 微服务异常传播机制

在微服务架构中,异常往往需要跨服务传播。我们需要设计合理的异常传播机制:

/**
 * 微服务异常传播工具类
 */
@Component
public class ServiceExceptionHandler {
    
    /**
     * 构建服务间传递的异常信息
     */
    public ServiceException buildServiceException(String service, Exception ex) {
        return new ServiceException(
            service,
            ex.getClass().getSimpleName(),
            ex.getMessage(),
            System.currentTimeMillis()
        );
    }
    
    /**
     * 从服务异常中恢复原始异常
     */
    public Exception restoreException(ServiceException serviceEx) {
        try {
            Class<? extends Exception> exceptionClass = 
                (Class<? extends Exception>) Class.forName(serviceEx.getExceptionType());
            return exceptionClass.getConstructor(String.class)
                                .newInstance(serviceEx.getMessage());
        } catch (Exception e) {
            return new RuntimeException("Failed to restore original exception", e);
        }
    }
}

/**
 * 服务异常类
 */
public class ServiceException extends RuntimeException {
    private String service;
    private String exceptionType;
    private long timestamp;
    
    public ServiceException(String service, String exceptionType, String message, long timestamp) {
        super(message);
        this.service = service;
        this.exceptionType = exceptionType;
        this.timestamp = timestamp;
    }
    
    // getter和setter方法
    public String getService() { return service; }
    public void setService(String service) { this.service = service; }
    
    public String getExceptionType() { return exceptionType; }
    public void setExceptionType(String exceptionType) { this.exceptionType = exceptionType; }
    
    public long getTimestamp() { return timestamp; }
    public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
}

4.2 Feign客户端异常处理

/**
 * Feign客户端配置和异常处理
 */
@Configuration
public class FeignConfig {
    
    @Bean
    public Request.Options options() {
        return new Request.Options(5000, 10000); // 连接超时5s,读取超时10s
    }
    
    @Bean
    public ErrorDecoder errorDecoder() {
        return new CustomErrorDecoder();
    }
}

/**
 * 自定义Feign错误解码器
 */
public class CustomErrorDecoder implements ErrorDecoder {
    
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    @Override
    public Exception decode(String methodKey, Response response) {
        try {
            // 读取响应体中的错误信息
            String body = Util.toString(response.body().asReader(StandardCharsets.UTF_8));
            
            if (response.status() >= 400 && response.status() < 500) {
                return new BusinessException(
                    "CLIENT_ERROR",
                    "Client error occurred: " + body
                );
            } else if (response.status() >= 500) {
                return new BusinessException(
                    "SERVER_ERROR",
                    "Server error occurred: " + body
                );
            }
        } catch (IOException e) {
            log.error("Failed to decode response body", e);
        }
        
        return new RuntimeException("Unknown error occurred");
    }
}

五、优雅降级策略实现

5.1 Hystrix/Resilience4j优雅降级

/**
 * 基于Resilience4j的优雅降级实现
 */
@Service
public class UserService {
    
    private final UserClient userClient;
    private final CircuitBreaker circuitBreaker;
    private final Retry retry;
    
    public UserService(UserClient userClient, CircuitBreakerRegistry registry) {
        this.userClient = userClient;
        this.circuitBreaker = registry.circuitBreaker("user-service");
        this.retry = Retry.ofDefaults("user-service");
    }
    
    /**
     * 获取用户信息 - 带降级
     */
    public User getUserById(Long id) {
        // 使用Resilience4j包装调用
        Supplier<User> userSupplier = () -> userClient.getUserById(id);
        
        return circuitBreaker.executeSupplier(
            retry.executeSupplier(userSupplier)
        );
    }
    
    /**
     * 获取用户信息 - 降级处理
     */
    public User getUserByIdWithFallback(Long id) {
        try {
            return circuitBreaker.executeSupplier(() -> userClient.getUserById(id));
        } catch (Exception e) {
            log.warn("Failed to get user from service, using fallback: {}", e.getMessage());
            // 返回默认用户信息或空值
            return new User(id, "Fallback User", "fallback@example.com");
        }
    }
}

5.2 服务降级策略配置

# application.yml
resilience4j:
  circuitbreaker:
    instances:
      user-service:
        failure-rate-threshold: 50
        wait-duration-in-open-state: 30s
        permitted-number-of-calls-in-half-open-state: 10
        sliding-window-size: 100
        sliding-window-type: COUNT_BASED
  retry:
    instances:
      user-service:
        max-attempts: 3
        wait-duration: 1000ms
        retryable-exceptions:
          - java.lang.RuntimeException
          - org.springframework.web.client.ResourceAccessException

5.3 自定义降级逻辑

/**
 * 自定义服务降级处理器
 */
@Component
public class ServiceFallbackHandler {
    
    private static final Logger log = LoggerFactory.getLogger(ServiceFallbackHandler.class);
    
    /**
     * 用户服务降级处理
     */
    public User getUserByIdFallback(Long id, Throwable throwable) {
        log.warn("User service fallback called for user id: {}, reason: {}", 
                id, throwable.getMessage());
        
        // 根据异常类型返回不同降级策略
        if (throwable instanceof TimeoutException) {
            return createDefaultUser(id, "Service timeout");
        } else if (throwable instanceof CircuitBreakerOpenException) {
            return createDefaultUser(id, "Service unavailable due to circuit breaker");
        } else {
            return createDefaultUser(id, "Service error occurred");
        }
    }
    
    /**
     * 创建默认用户
     */
    private User createDefaultUser(Long id, String reason) {
        return new User(
            id,
            "Default User " + id,
            "default" + id + "@example.com",
            reason
        );
    }
}

六、异常处理最佳实践

6.1 异常日志记录策略

/**
 * 完善的异常日志记录
 */
@Component
@Slf4j
public class ExceptionLoggingService {
    
    /**
     * 记录详细异常信息
     */
    public void logException(Exception ex, String context, Map<String, Object> additionalInfo) {
        // 构建详细的异常日志
        StringBuilder logMessage = new StringBuilder();
        logMessage.append("Exception occurred in ").append(context).append("\n");
        logMessage.append("Exception type: ").append(ex.getClass().getName()).append("\n");
        logMessage.append("Exception message: ").append(ex.getMessage()).append("\n");
        
        if (additionalInfo != null) {
            additionalInfo.forEach((key, value) -> 
                logMessage.append(key).append(": ").append(value).append("\n")
            );
        }
        
        // 记录堆栈跟踪
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        ex.printStackTrace(pw);
        logMessage.append("Stack trace:\n").append(sw.toString());
        
        log.error(logMessage.toString());
    }
    
    /**
     * 记录业务异常
     */
    public void logBusinessException(BusinessException ex, String context) {
        Map<String, Object> additionalInfo = new HashMap<>();
        additionalInfo.put("code", ex.getCode());
        additionalInfo.put("args", Arrays.toString(ex.getArgs()));
        
        logException(ex, context, additionalInfo);
    }
}

6.2 异常响应格式标准化

/**
 * 统一异常响应格式
 */
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;
    private long timestamp;
    private String traceId;
    
    public ApiResponse() {
        this.timestamp = System.currentTimeMillis();
        this.traceId = UUID.randomUUID().toString();
    }
    
    public ApiResponse(int code, String message) {
        this();
        this.code = code;
        this.message = message;
    }
    
    public ApiResponse(int code, String message, T data) {
        this(code, message);
        this.data = data;
    }
    
    // 静态工厂方法
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(0, "success", data);
    }
    
    public static <T> ApiResponse<T> error(int code, String message) {
        return new ApiResponse<>(code, message);
    }
    
    public static <T> ApiResponse<T> error(String message) {
        return new ApiResponse<>(500, message);
    }
    
    // getter和setter方法
    public int getCode() { return code; }
    public void setCode(int code) { this.code = code; }
    
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    
    public T getData() { return data; }
    public void setData(T data) { this.data = data; }
    
    public long getTimestamp() { return timestamp; }
    public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
    
    public String getTraceId() { return traceId; }
    public void setTraceId(String traceId) { this.traceId = traceId; }
}

6.3 异常处理性能优化

/**
 * 异常处理性能优化
 */
@Component
public class OptimizedExceptionHandler {
    
    private static final Logger log = LoggerFactory.getLogger(OptimizedExceptionHandler.class);
    
    /**
     * 异步记录异常日志
     */
    @Async
    public void asyncLogException(Exception ex, String context) {
        // 使用异步方式记录日志,避免阻塞主线程
        log.error("Async exception logging - Context: {}, Message: {}", 
                 context, ex.getMessage(), ex);
    }
    
    /**
     * 异常频率限制
     */
    private final Map<String, Long> exceptionCounter = new ConcurrentHashMap<>();
    private static final long TIME_WINDOW_MS = 60000; // 1分钟窗口
    
    public boolean shouldLogException(String exceptionKey) {
        long now = System.currentTimeMillis();
        Long lastTime = exceptionCounter.get(exceptionKey);
        
        if (lastTime == null || now - lastTime > TIME_WINDOW_MS) {
            exceptionCounter.put(exceptionKey, now);
            return true;
        }
        
        return false; // 在时间窗口内,不记录重复异常
    }
    
    /**
     * 异常统计监控
     */
    public void monitorException(Exception ex, String context) {
        // 统计异常发生次数
        String key = ex.getClass().getSimpleName() + "_" + context;
        Metrics.counter("exception_count", "type", ex.getClass().getSimpleName(), 
                       "context", context).increment();
    }
}

七、完整示例项目结构

7.1 项目目录结构

src/
├── main/
│   ├── java/
│   │   └── com/example/demo/
│   │       ├── exception/
│   │       │   ├── BusinessException.java
│   │       │   ├── ErrorCode.java
│   │       │   ├── ErrorResponse.java
│   │       │   └── GlobalExceptionHandler.java
│   │       ├── config/
│   │       │   └── WebConfig.java
│   │       ├── controller/
│   │       │   └── UserController.java
│   │       ├── service/
│   │       │   └── UserService.java
│   │       └── DemoApplication.java
│   └── resources/
│       ├── application.yml
│       └── messages.properties

7.2 完整控制器示例

/**
 * 用户控制器示例
 */
@RestController
@RequestMapping("/api/users")
@Slf4j
public class UserController {
    
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    /**
     * 获取用户信息
     */
    @GetMapping("/{id}")
    public ApiResponse<User> getUser(@PathVariable Long id) {
        try {
            User user = userService.getUserById(id);
            return ApiResponse.success(user);
        } catch (ResourceNotFoundException ex) {
            log.warn("User not found: {}", id);
            throw ex; // 交给全局异常处理器处理
        } catch (Exception ex) {
            log.error("Failed to get user: {}", id, ex);
            throw new BusinessException("INTERNAL_ERROR", "Failed to retrieve user");
        }
    }
    
    /**
     * 创建用户
     */
    @PostMapping
    public ApiResponse<User> createUser(@Valid @RequestBody CreateUserRequest request) {
        try {
            User user = userService.createUser(request);
            return ApiResponse.success(user);
        } catch (ValidationException ex) {
            log.warn("Validation failed: {}", ex.getMessage());
            throw ex;
        } catch (BusinessException ex) {
            log.warn("Business exception: {}", ex.getMessage());
            throw ex;
        } catch (Exception ex) {
            log.error("Failed to create user", ex);
            throw new BusinessException("INTERNAL_ERROR", "Failed to create user");
        }
    }
    
    /**
     * 更新用户
     */
    @PutMapping("/{id}")
    public ApiResponse<User> updateUser(@PathVariable Long id, 
                                       @Valid @RequestBody UpdateUserRequest request) {
        try {
            User user = userService.updateUser(id, request);
            return ApiResponse.success(user);
        } catch (ResourceNotFoundException ex) {
            log.warn("User not found: {}", id);
            throw ex;
        } catch (Exception ex) {
            log.error("Failed to update user: {}", id, ex);
            throw new BusinessException("INTERNAL_ERROR", "Failed to update user");
        }
    }
}

八、总结与展望

通过本文的详细介绍,我们全面了解了Spring Boot异常处理的核心概念和实践方法。从基础的自定义异常设计,到全局异常捕获机制,再到微服务场景下的优雅降级策略,每一个环节都至关重要。

关键要点回顾:

  1. 自定义异常类:创建语义清晰、结构化的业务异常类
  2. 全局异常处理:使用@ControllerAdvice统一处理各类异常
  3. 微服务异常传播:设计合理的异常传递和降级机制
  4. 优雅降级策略:实现服务熔断、重试等容错机制
  5. 最佳实践:包括日志记录、响应格式标准化、性能优化等

未来发展趋势:

随着Spring Cloud生态系统的发展,我们期待看到:

  • 更加智能化的异常检测和处理机制
  • 与可观测性工具更深度的集成
  • 基于AI的异常预测和自动修复能力
  • 更完善的微服务间异常传递协议

通过构建健壮的异常处理体系,我们不仅能够提升应用

相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000