🎉🎉《Spring Boot实战案例合集》目前已更新148个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
在 Web 项目开发中,超大 JSON 数据请求的情况愈发常见,比如物联网设备批量上传海量监测数据、大数据分析系统接收大规模用户行为信息等场景。
超大 JSON 数据不仅数据量庞大,可能达到几十兆甚至上百兆,而且内部结构复杂,嵌套层级深、字段繁多。若处理不当,会引发诸多问题,如内存溢出,导致应用崩溃;数据解析耗时过长,降低系统响应速度,影响用户体验;还可能因数据传输不稳定,造成数据丢失或损坏。
因此,如何让 Spring Boot 应用高效、稳定地处理超大 JSON 数据请求,成为保障系统性能与可靠性的关键。
在本篇文章中,我们将运用三种不同的方法,对处理超大 JSON 数据的性能展开对比分析。
准备数据
public record User(Long id, String name, Integer age, String sex, String email, String address) {}
准备了50W条json数据
接下来的测试都是基于此数据进行测试。
2.1 普通处理方式
("/normal")public ResponseEntity<String> normal( List<User> datas) {datas.forEach(this::processItem) ;try {TimeUnit.MILLISECONDS.sleep(2000) ;} catch (InterruptedException e) {}return ResponseEntity.ok("normal success") ;}private void processItem(User item) {// todo}
这是一个普通 POST 请求处理方法。使用 @RequestBody 接收客户端传来的 List<User> 类型 JSON 数据。这种方式在数据量大时可能因同步处理和内存占用导致性能瓶颈。
如下,通过JConsole查看,在处理整个请求过程中内存的变化情况:
只要进入到该方法中内存就已经暴增到最高点。
2.2 使用流式解析
使用 Jackson 的 JsonParser 逐块读取数据,不加载整个 JSON 到内存。
public ResponseEntity<String> stream(InputStream inputStream) throws IOException {ObjectMapper mapper = new ObjectMapper();try (JsonParser parser = mapper.getFactory().createParser(inputStream)) {// 遍历 JSON 结构JsonToken token;while ((token = parser.nextToken()) != null) {if (token == JsonToken.START_ARRAY) {while (parser.nextToken() != JsonToken.END_ARRAY) {// 逐条处理数组中的对象User item = parser.readValueAs(User.class) ;processItem(item);}}}}try {TimeUnit.MILLISECONDS.sleep(2000) ;} catch (InterruptedException e) {}return ResponseEntity.ok("stream success");}
通过流式处理超大 JSON 数据。利用 InputStream 读取数据,借助 JsonParser 逐个解析 JSON 令牌。当遇到数组起始时,逐条读取并处理 User 对象,避免一次性加载全部数据到内存,有效降低内存占用。
如下,通过JConsole查看,在处理整个请求过程中内存的变化情况:
整体内存变化非常的小。当我们没有进入while循环处理的时候,内存基本是没有变化的,只有再真正处理数据的时候,内存才会递增。
2.3 使用响应式WebFlux
使用 Spring WebFlux 实现非阻塞流式处理。
public Mono<String> fluxJson( Flux<User> items) {return items.doOnNext(this::processItem).doOnComplete(() -> {System.err.println("处理完成...") ;}).then(Mono.just("flux success")).delayElement(Duration.ofSeconds(2)) ;}
访问该接口,最终内存情况如下:
与上面的InputStream处理方式一样,只要没有开始处理数据,内存基本不会变化,只有开始处理后内存才开始递增。
推荐文章
都2025年了,Spring Boot开发中的这些错误不要再犯了
天呐!Java Stream 高效开发!16 个逆天案例,让你秒速起飞!
优雅!Spring Boot 只需一个注解,搞定任意参数验证
王炸!Spring AI+Tools 一分钟实现CRUD智能助手
告别内存溢出!Spring StreamingResponseBody 三大实战案例,性能提升100%
Spring Boot文件上传5种玩法!@RequestPart最强大


