MultipartFile类型接收上传文件报出的UncheckedIOException以及删除tomcat临时文件失败源码探索

1、描述异常背景:

因为需要分析数据,待处理excel文件的数据行数太大,手动太累,花半小时写了一个定制的数据入库工具,改成了通用的,整个项目中的万级别数据都在工具上分析,写SQL进行分析,但是遇到很疑惑的问题,文件上传结束收流时,tomcat的DisFileItem类的delete方法会自动调用,但是如果当前系统用户的权限不足,或是文件流在删除该临时文件之前未关闭都会导致删除失败,虽然接收流的业务操作都结束了,但是很是会报出糟心的UncheckedIOException:Cannot delete tomcat默认的临时文件路径+_00000000.tmp异常(剧透一下:运行时未关闭输入流,JVM还在等待用户关闭,存在引用无法回收,所以手动跟着路径去删除你都删不掉,所以跟着源码找根源)。

2、查找异常原因(并不是所有的异常都是你显式的写出来的,特别是轮子使用不仔细的内部异常)

以上请及其注意异常出现的根源:StandardServletMultipartResolver.java:134;

我们进去查看其源码得到

也就是说我们的请求文件接收成功了吗,但是删除临时文件的操作出现问题了:

java 复制代码
if (request.getFile(part.getName()) != null) {
                        part.delete();
   }

进入删除的代码下来:

注意这一句源码注释:

删除部件的基础存储,包括删除任何关联的临时磁盘文件。尽管容器将自动删除此存储,但此方法可用于确保在较早的时间执行此操作,从而保留系统资源。

仅当对部件实例进行垃圾回收时,才需要容器删除关联的存储。Apache Tomcat 将在关联的请求完成处理后删除关联的存储。其他容器的行为可能不同。

抛出:

IOException -- 如果在尝试删除部件时发生 I/O

那么我们进入到它的默认实现类的最终源码:

到这里我们大致是知道问题出在这个临时文件的删除上了。

但是为什么删除失败呢?只有可能是这行代码的问题:

如果输出的文件就是有问题的null那一定是删除不掉的,让我们找找源码:

这里一定是没有问题的,继续往下走:

由此处的信息可以知道作为缓冲的临时文件区域的输出流未完成,还在保持开启状态,很大的可能是缓冲前的输入的流还没完全关闭(我们明确知道的是在代码里获取了输入的流但是没有对流进行关闭),亦或有可能原本文件上传就是null(当然不可能了兄弟)

3、结合2查找真正导致输出文件流在删除之前关闭的原因

我们注意到简单的接口代码是:

java 复制代码
    @PostMapping("/upTopGoods")
    @ResponseBody
    public void upTopGoods(@RequestParam("fileName") MultipartFile fileName){
        if (Objects.nonNull(fileName)){
            excelUtil.setTopGoods(fileName);
        }
    }

这个流会在操作完成或输入流的字节被处理完之后没能主动关闭的话,很有可能出自于接口MultipartFile的性质需要我们自己关闭(所以才会有一次OOM异常,但是请注意一定不仅仅是这个导致的,BUG选手程序员要保持疑问)。

所以我们查看MultipartFile的源码试图找出问题所在:

以上是MultipartFile的输入流方法注释。

以上处理完数据之后我们对输入的流进行了关闭,测试一下看看是否解决了问题:

通过结果来看是完全没有问题的了。

本次排查问题寻根原理过程结束,拜拜!

相关推荐
X***07881 分钟前
从语言演进到工程实践全面解析C++在现代软件开发中的设计思想性能优势与长期生命力
java·开发语言
smileNicky7 分钟前
SpringBoot系列之集成Pulsar教程
java·spring boot·后端
Sammyyyyy27 分钟前
Rust 1.92.0 发布:Never Type 进一步稳定
java·算法·rust
alonewolf_9937 分钟前
深入解析G1与ZGC垃圾收集器:原理、调优与选型指南
java·jvm·算法
小镇学者39 分钟前
【c++】C++字符串删除末尾字符的三种实现方法
java·开发语言·c++
rfidunion40 分钟前
springboot+VUE+部署(1。新建项目)
java·vue.js·spring boot
小翰子_41 分钟前
Spring Boot整合Sharding-JDBC实现日志表按月按周分表实战
java·spring boot·后端
weixin_399380691 小时前
OA 系统假死问题分析与优化
java·运维
豆沙沙包?1 小时前
2026年--Lc334-2130. 链表最大孪生和(链表转数组)--java版
java·数据结构·链表
柒.梧.1 小时前
SSM常见核心面试问题深度解析
java·spring·面试·职场和发展·mybatis