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

如何优雅处理Spring Boot服务层异常?

优雅处理Spring Boot服务层异常的几种方案

方案一:自定义业务异常 + 全局异常处理器

这是最贴合Spring分层思想的方案:服务层只负责抛出语义明确的自定义业务异常,异常统一由上层的@ControllerAdvice全局处理器捕获处理,既不破坏分层逻辑,又能统一异常响应格式。

  1. 定义自定义业务异常
public class BusinessException extends RuntimeException {
    private Integer code;
    private String message;

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }

    // getter方法省略
}
  1. 服务层抛出业务异常
@Service
public class UserService {
    public void updateUser(Long userId) {
        if (userId == null || userId <= 0) {
            throw new BusinessException(400, "用户ID不合法");
        }
        // 执行业务逻辑,若遇底层异常(如数据库异常),也可转换为业务异常抛出
        try {
            // 数据库操作
        } catch (DataAccessException e) {
            throw new BusinessException(500, "用户信息更新失败");
        }
    }
}
  1. 全局处理器捕获处理
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResponseEntity<Map<String, Object>> handleBusinessException(BusinessException e) {
        Map<String, Object> result = new HashMap<>();
        result.put("code", e.getCode());
        result.put("message", e.getMessage());
        return new ResponseEntity<>(result, HttpStatus.valueOf(e.getCode()));
    }

    // 可额外处理其他系统异常,如RuntimeException、IOException等
}

方案二:AOP + 自定义注解实现精准异常处理

如果部分服务方法需要局部异常处理(比如返回默认值、做补偿操作,而非抛到控制器层),可以用AOP结合自定义注解,只对标记的方法做异常处理,避免@Around捕获所有方法造成资源浪费。

  1. 定义自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HandleServiceException {
    // 可添加属性,比如指定默认返回值类型
}
  1. 编写AOP切面
@Aspect
@Component
public class ServiceExceptionAspect {
    private static final Logger logger = LoggerFactory.getLogger(ServiceExceptionAspect.class);

    @Pointcut("@annotation(com.example.demo.HandleServiceException)")
    public void serviceExceptionPointcut() {}

    @Around("serviceExceptionPointcut()")
    public Object handleException(ProceedingJoinPoint joinPoint) {
        try {
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            // 记录异常日志
            logger.error("服务方法执行异常,方法名:{},参数:{}",
                    joinPoint.getSignature().getName(),
                    Arrays.toString(joinPoint.getArgs()),
                    throwable);
            
            // 根据异常类型做不同处理,比如返回默认值
            if (throwable instanceof BusinessException) {
                return new ErrorResponse(((BusinessException) throwable).getCode(), throwable.getMessage());
            }
            // 未知异常返回默认兜底响应
            return new ErrorResponse(500, "服务内部处理异常");
        }
    }
}
  1. 服务层方法标记注解
@Service
public class OrderService {
    @HandleServiceException
    public Order getOrder(Long orderId) {
        if (orderId <= 0) {
            throw new BusinessException(400, "订单ID不合法");
        }
        return orderRepository.findById(orderId)
                .orElseThrow(() -> new RuntimeException("订单不存在"));
    }
}

方案三:服务层局部异常转换

对于不需要抛到上层的底层异常(如数据库操作异常、第三方调用异常),可以在服务层局部捕获并转换为业务友好的提示,或者做降级处理,避免上层感知到底层实现细节。

@Service
public class ProductService {
    public List<Product> getHotProducts() {
        try {
            return productRepository.findHotProducts();
        } catch (DataAccessException e) {
            logger.error("热门商品查询失败", e);
            // 降级处理,返回空列表或默认数据
            return Collections.emptyList();
        }
    }
}

内容的提问来源于stack exchange,提问作者buzz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 08:20:26