Spring Boot3中@Size验证大List引发CPU占满,该如何解决?
问题分析与解决方案
这是不是@Size的Bug?
不是Bug。原因在于:@Size注解验证List集合大小的前提是请求体已经被完整反序列化为List对象,当传入70万条数据时,Spring需要先把整个JSON请求体转换成包含70万个TestDTO实例的List,这个反序列化过程本身就会消耗大量CPU资源(解析超大规模JSON、创建大量对象),导致CPU占用率拉满。@Size只是在反序列化完成后读取集合size做判断,它本身的逻辑非常简单,并没有性能问题。
其他解决方案
除了限制请求体大小,你可以尝试以下几种方案:
提前拦截超大规模请求
通过Spring Boot配置在请求到达控制器前直接拦截过大的请求体,避免进入反序列化流程。在application.yml或application.properties中配置:server: tomcat: max-http-post-size: 5MB # 根据单条TestDTO的大小估算,比如每条100字节,3条仅300字节,设置远低于70万条对应的大小 connection-timeout: 2000 # 可选,缩短超时时间快速拒绝大请求自定义前置验证拦截器
编写一个Filter或Interceptor,在请求进入控制器前先读取请求体的字节长度,结合单条TestDTO的预估大小计算大致条数,若超过限制(比如3条)直接返回错误响应,无需反序列化整个集合。注意要使用ContentCachingRequestWrapper包装请求,避免请求体被读取后无法再次使用:@Component public class RequestSizeFilter extends OncePerRequestFilter { private static final int MAX_ALLOWED_BYTES = 300; // 假设3条TestDTO约300字节 @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request); byte[] requestBody = wrappedRequest.getContentAsByteArray(); if (requestBody.length > MAX_ALLOWED_BYTES) { response.setStatus(HttpStatus.BAD_REQUEST.value()); response.getWriter().write("请求数据条数超过限制"); return; } filterChain.doFilter(wrappedRequest, response); } }调整接口接收方式
如果业务允许,避免一次性接收大量集合数据:- 将接口改为分批接收数据,比如每次最多传3条;
- 改用
@RequestParam接收单个参数,而非整个List集合。
优化验证注解的使用
确保控制器类上的@Validated和方法参数的@Valid注解没有重复触发不必要的验证。你当前代码中@RequestBody前有两个@Valid,可以去掉一个,避免重复验证开销。
内容的提问来源于stack exchange,提问作者user24450259
相关产品推荐
相关产品推荐

