SpringBoot实战:从零构建高可用REST API的7个核心技巧

7次阅读
没有评论

共计 3545 个字符,预计需要花费 9 分钟才能阅读完成。

image.webp

线上事故引发的思考

去年我们团队遭遇过一次严重的线上故障:用户提交订单时偶发 500 错误,由于未正确处理NullPointerException,导致错误蔓延至网关层,最终引发服务雪崩。事后分析发现两个关键问题:

SpringBoot 实战:从零构建高可用 REST API 的 7 个核心技巧

  • 线程池采用 Tomcat 默认配置,突发流量下请求堆积
  • 异常信息直接返回前端,暴露内部表结构

这次事故让我们意识到:生产级 API 必须具备完善的防御性编程机制。下面分享 7 个经过实战验证的优化方案。

核心技术方案

1. 线程池优化实战

SpringBoot 默认使用 Tomcat 线程池,配置参数如下:

# 默认配置(不推荐)server.tomcat.threads.max=200
server.tomcat.threads.min-spare=10

通过 Jmeter 压测发现:当并发请求达到 150 时,99 线响应时间从 50ms 飙升到 800ms。优化方案:

@Configuration
public class ThreadPoolConfig {
    /**
     * 自定义线程池
     * 核心线程数 = CPU 核心数 * 2
     * 最大队列长度 = 核心线程数 * 5
     */
    @Bean
    public ExecutorService apiExecutor() {int coreSize = Runtime.getRuntime().availableProcessors() * 2;
        return new ThreadPoolExecutor(
            coreSize, 
            coreSize * 2,
            60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(coreSize * 5),
            new ThreadPoolExecutor.CallerRunsPolicy() // 重要!避免任务丢失);
    }
}

优化后对比数据:

指标 默认配置 优化配置
500 并发 RT99 1200ms 350ms
错误率 8.7% 0.2%

2. 全局异常处理

推荐使用 @ControllerAdvice 实现三层异常捕获:

@ControllerAdvice
public class GlobalExceptionHandler {

    // 处理业务异常
    @ExceptionHandler(BizException.class)
    public ResponseEntity<ResultVO<?>> handleBizException(BizException e) {return ResponseEntity.status(e.getCode())
            .body(ResultVO.error(e.getCode(), e.getMessage()));
    }

    // 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ResultVO<?>> handleValidException(MethodArgumentNotValidException e) {String message = e.getBindingResult().getAllErrors()
            .stream()
            .map(DefaultMessageSourceResolvable::getDefaultMessage)
            .collect(Collectors.joining(";"));
        return ResponseEntity.badRequest()
            .body(ResultVO.error(400, message));
    }

    // 兜底异常处理
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ResultVO<?>> handleException(Exception e) {log.error("系统异常", e);
        return ResponseEntity.internalServerError()
            .body(ResultVO.error(500, "系统繁忙,请稍后重试"));
    }
}

3. DTO 验证进阶

基础校验(使用@Valid):

@Data
public class UserDTO {@NotBlank(message = "用户名不能为空")
    @Size(max = 20, message = "用户名长度超限")
    private String username;

    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
    private String mobile;
}

@PostMapping("/users")
public ResultVO<String> createUser(@Valid @RequestBody UserDTO dto) {// 业务逻辑}

自定义校验器示例(检查密码强度):

@Documented
@Constraint(validatedBy = PasswordValidator.class)
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface StrongPassword {String message() default "密码必须包含大小写字母和数字";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};}

public class PasswordValidator implements ConstraintValidator<StrongPassword, String> {private static final Pattern PATTERN = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {return value != null && PATTERN.matcher(value).matches();}
}

4. 响应标准化设计

通用响应体模板:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultVO<T> implements Serializable {
    private Integer code;
    private String message;
    private T data;
    private long timestamp = System.currentTimeMillis();

    public static <T> ResultVO<T> success(T data) {return new ResultVO<>(200, "success", data);
    }

    public static <T> ResultVO<T> error(int code, String message) {return new ResultVO<>(code, message, null);
    }
}

生产环境检查清单

必须开启的 Actuator 端点

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,threaddump
  endpoint:
    health:
      show-details: always

日志脱敏正则

// 手机号 / 身份证脱敏
logback.xml 配置:<conversionRule conversionWord="msg" 
  converterClass="com.util.SensitiveDataConverter"/>

// 实现类关键代码:String pattern = "(?<=[^0-9a-zA-Z])(1[3-9]\\d{2})(\\d{4})(\\d{4})(?=[^0-9a-zA-Z])";
return message.replaceAll(pattern, "$1****$3");

Prometheus 关键指标

# 接口成功率
sum(rate(http_server_requests_seconds_count{status=~"2.."}[1m])) 
  / sum(rate(http_server_requests_seconds_count[1m]))

# 线程池使用率
thread_pool_active_threads / thread_pool_max_threads

开放性问题

在微服务架构下,我们既需要统一的异常处理机制保证系统健壮性,又要允许业务服务定制特殊错误码。如何设计既能通过 @ControllerAdvice 实现全局拦截,又能支持服务自定义异常类型?欢迎在评论区分享你的方案。

正文完
 0
评论(没有评论)