1、描述異常背景:
因?yàn)樾枰治鰯?shù)據(jù),待處理excel文件的數(shù)據(jù)行數(shù)太大,手動(dòng)太累,花半小時(shí)寫(xiě)了一個(gè)定制的數(shù)據(jù)入庫(kù)工具,改成了通用的,整個(gè)項(xiàng)目中的萬(wàn)級(jí)別數(shù)據(jù)都在工具上分析,寫(xiě)SQL進(jìn)行分析,但是遇到很疑惑的問(wèn)題,文件上傳結(jié)束收流時(shí),tomcat的DisFileItem類的delete方法會(huì)自動(dòng)調(diào)用,但是如果當(dāng)前系統(tǒng)用戶的權(quán)限不足,或是文件流在刪除該臨時(shí)文件之前未關(guān)閉都會(huì)導(dǎo)致刪除失敗,雖然接收流的業(yè)務(wù)操作都結(jié)束了,但是很是會(huì)報(bào)出糟心的UncheckedIOException:Cannot delete? tomcat默認(rèn)的臨時(shí)文件路徑+_00000000.tmp異常(劇透一下:運(yùn)行時(shí)未關(guān)閉輸入流,JVM還在等待用戶關(guān)閉,存在引用無(wú)法回收,所以手動(dòng)跟著路徑去刪除你都刪不掉,所以跟著源碼找根源)。
2、查找異常原因(并不是所有的異常都是你顯式的寫(xiě)出來(lái)的,特別是輪子使用不仔細(xì)的內(nèi)部異常)
?以上請(qǐng)及其注意異常出現(xiàn)的根源:StandardServletMultipartResolver.java:134;
我們進(jìn)去查看其源碼得到
?也就是說(shuō)我們的請(qǐng)求文件接收成功了嗎,但是刪除臨時(shí)文件的操作出現(xiàn)問(wèn)題了:
if (request.getFile(part.getName()) != null) {
part.delete();
}
進(jìn)入刪除的代碼下來(lái):
注意這一句源碼注釋:
?刪除部件的基礎(chǔ)存儲(chǔ),包括刪除任何關(guān)聯(lián)的臨時(shí)磁盤(pán)文件。盡管容器將自動(dòng)刪除此存儲(chǔ),但此方法可用于確保在較早的時(shí)間執(zhí)行此操作,從而保留系統(tǒng)資源。
僅當(dāng)對(duì)部件實(shí)例進(jìn)行垃圾回收時(shí),才需要容器刪除關(guān)聯(lián)的存儲(chǔ)。Apache Tomcat 將在關(guān)聯(lián)的請(qǐng)求完成處理后刪除關(guān)聯(lián)的存儲(chǔ)。其他容器的行為可能不同。
拋出:
IOException – 如果在嘗試刪除部件時(shí)發(fā)生 I/O
那么我們進(jìn)入到它的默認(rèn)實(shí)現(xiàn)類的最終源碼:
?
?到這里我們大致是知道問(wèn)題出在這個(gè)臨時(shí)文件的刪除上了。
?但是為什么刪除失敗呢?只有可能是這行代碼的問(wèn)題:
?如果輸出的文件就是有問(wèn)題的null那一定是刪除不掉的,讓我們找找源碼:
?這里一定是沒(méi)有問(wèn)題的,繼續(xù)往下走:
?由此處的信息可以知道作為緩沖的臨時(shí)文件區(qū)域的輸出流未完成,還在保持開(kāi)啟狀態(tài),很大的可能是緩沖前的輸入的流還沒(méi)完全關(guān)閉(我們明確知道的是在代碼里獲取了輸入的流但是沒(méi)有對(duì)流進(jìn)行關(guān)閉),亦或有可能原本文件上傳就是null(當(dāng)然不可能了兄弟)
3、結(jié)合2查找真正導(dǎo)致輸出文件流在刪除之前關(guān)閉的原因
我們注意到簡(jiǎn)單的接口代碼是:
@PostMapping("/upTopGoods")
@ResponseBody
public void upTopGoods(@RequestParam("fileName") MultipartFile fileName){
if (Objects.nonNull(fileName)){
excelUtil.setTopGoods(fileName);
}
}
這個(gè)流會(huì)在操作完成或輸入流的字節(jié)被處理完之后沒(méi)能主動(dòng)關(guān)閉的話,很有可能出自于接口MultipartFile的性質(zhì)需要我們自己關(guān)閉(所以才會(huì)有一次OOM異常,但是請(qǐng)注意一定不僅僅是這個(gè)導(dǎo)致的,BUG選手程序員要保持疑問(wèn))。
所以我們查看MultipartFile的源碼試圖找出問(wèn)題所在:
?以上是MultipartFile的輸入流方法注釋。
以上處理完數(shù)據(jù)之后我們對(duì)輸入的流進(jìn)行了關(guān)閉,測(cè)試一下看看是否解決了問(wèn)題:
?
?通過(guò)結(jié)果來(lái)看是完全沒(méi)有問(wèn)題的了。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-615921.html
本次排查問(wèn)題尋根原理過(guò)程結(jié)束,拜拜!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-615921.html
到了這里,關(guān)于MultipartFile類型接收上傳文件報(bào)出的UncheckedIOException以及刪除tomcat臨時(shí)文件失敗源碼探索的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!