現(xiàn)象描述:
為新邵等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及新邵網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、新邵網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!
項目使用springboot啟動一個web項目,在啟動階段看到console中出現(xiàn)了異?!?.10.3-1.4.3\hdf5.jar 系統(tǒng)找不到指定的文件”,雖然這些異常不影響項目的正常運行,但作為一個嚴謹?shù)募夹g(shù)人員,看到這些異常就像見到仇人一樣,一定要除之而后快。
java.io.FileNotFoundException: D:\.m2\repository\org\bytedeco\javacpp-presets\hdf5-platform\1.10.3-1.4.3\hdf5.jar (系統(tǒng)找不到指定的文件。) at java.util.zip.ZipFile.open(Native Method) at java.util.zip.ZipFile.(ZipFile.java:225) at java.util.zip.ZipFile. (ZipFile.java:155) at java.util.jar.JarFile. (JarFile.java:166) at java.util.jar.JarFile. (JarFile.java:130) at org.apache.tomcat.util.compat.JreCompat.jarFileNewInstance(JreCompat.java:188) at org.apache.tomcat.util.scan.JarFileUrlJar. (JarFileUrlJar.java:65) at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:49) at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:374) at org.apache.tomcat.util.scan.StandardJarScanner.processURLs(StandardJarScanner.java:309) at org.apache.tomcat.util.scan.StandardJarScanner.doScanClassPath(StandardJarScanner.java:266) at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:229) at org.apache.jasper.servlet.TldScanner.scanJars(TldScanner.java:262) at org.apache.jasper.servlet.TldScanner.scan(TldScanner.java:104) at org.apache.jasper.servlet.JasperInitializer.onStartup(JasperInitializer.java:101) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5204) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411) at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) 2019-03-29 18:09:08.303 WARN 16940 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner : Failed to scan [file:/D:/.m2/repository/org/bytedeco/javacpp-presets/hdf5-platform/1.10.3-1.4.3/hdf5-linux-x86.jar] from classloader hierarchy java.io.FileNotFoundException: D:\.m2\repository\org\bytedeco\javacpp-presets\hdf5-platform\1.10.3-1.4.3\hdf5-linux-x86.jar (系統(tǒng)找不到指定的文件。) ...... 2019-03-29 18:09:08.578 WARN 16940 --- [ost-startStop-1] o.a.tomcat.util.scan.StandardJarScanner : Failed to scan [file:/D:/.m2/repository/org/bytedeco/javacpp-presets/hdf5-platform/1.10.3-1.4.3/hdf5-linux-x86_64.jar] from classloader hierarchy java.io.FileNotFoundException: D:\.m2\repository\org\bytedeco\javacpp-presets\hdf5-platform\1.10.3-1.4.3\hdf5-linux-x86_64.jar (系統(tǒng)找不到指定的文件。)
項目環(huán)境說明
org.deeplearning4j deeplearning4j-core 1.0.0-beta3
有問題的jar依賴關(guān)系
跟蹤分析
既然是在啟動階段報錯,那就找到啟動類添加斷點,一步步跟蹤下到底哪個階段報的錯誤,然后再分析出錯的原因。我跟蹤調(diào)試了springboot的代碼,找到j(luò)ar的加載位置。主要的幾個類和方法如下所示:
跟蹤類org.apache.tomcat.util.scan.StandardJarScanner
方法doScanClassPath(...)
該方法會對所有classloader進行遍歷,加載每一個classloader中jar包
上圖標紅處就是關(guān)鍵代碼,其中變量classPathUrlsToProcess中存放的是所有待加載的jar信息,主要是jar包路徑信息,我們可以看到這里面和我們在maven中看到的jar包是一樣的。
該方法會對當前classloader的所有jar,也就是對classPathUrlsToProcess進行堆棧操作,然后處理每一個jar包。關(guān)鍵代碼如下所示。
該方法會對每一個jar進行加載及分析處理,該方法中重點關(guān)注
processManifest(jar, isWebapp, classPathUrlsToProcess)
該方法會處理jar中的Manifest文件,對Manifest文件中的Class-Path進行分隔處理,對其中的內(nèi)容作為新的依賴jar再插入到classPathUrlsToProcess中(processURLs方法會按照堆棧結(jié)果加載其中的jar)
原因分析
其實問題就是出Manifest文件中的classpath,通過分析代碼我們知道tomcat除了加載了我們maven管理的jar包之外,還會對jar中的manifest文件進行分析,如果其中存在classpath,他會將其中的內(nèi)容也添加jar包依賴中,并對這些jar包進行加載。
我們打開其中hdf5-1.10.3-1.4.3.jar的manifest文件作為例子看看錯誤出在哪里。
大家注意到了沒有,這里的jar包沒有路徑也沒有版本號,這就導致tomcat加載的時候按照hdf5-1.10.3-1.4.3.jar的路徑進行加載。
然而我們的工程中在對應(yīng)位置并不存在這些jar,這也就導致了找不到j(luò)ar的異常。我們工程中實際上有這些jar,只不過路徑和名字不一樣。在上圖左邊大家可以看到maven中其實已經(jīng)有了這些jar,只不過名字后面多了版本號,路徑在各自的maven倉庫中。
到這里我們已經(jīng)將出現(xiàn)問題的原因弄清楚了,接下來我們考慮下怎么解決。
解決方案
方案一:
刪除Manifest中的classpath或者刪除Manifest文件,這樣就避免了加載不存在的jar包。但是每次maven更新的時候可能會覆蓋掉你的修改,導致異常再次出現(xiàn)。
方案二:
按照加載提示的路徑,將對應(yīng)jar包復制過去并改名去掉版本號,但這樣會造成jar冗余,同樣的jar會加載兩個。
方案三:
降級tomcat版本,使用8.5.0 或以下版本。8.5.0版本中不會對manifest進行分析加載,這樣也就不會出現(xiàn)我們的異常了。
方案四
增加一下代碼設(shè)置不掃描Manifest文件。
@Bean public TomcatServletWebServerFactory tomcatFactory() { return new TomcatServletWebServerFactory() { @Override protected void postProcessContext(Context context) { ((StandardJarScanner) context.getJarScanner()).setScanManifest(false); } }; }
總結(jié):
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對創(chuàng)新互聯(lián)的支持。