ClassLoader.getSystemResourceAsStream("a.txt")獲取不到資源文件


一、解決方案

換成XXX.class.getClassLoader().getResourceAsStream("a.txt")即可。

二、場景復現

src/main/resource下存在文件a.txt,項目類中static 方法中讀取該文件。ClassLoader.getSystemResourceAsStream("a.txt")獲取不到資源文件

三、原因剖析

getResourceAsStream會先使用本類的類加載器去加載,本類沒有類加載器,才會使用系統類加載器。也就是說getResourceAsStream功能覆蓋了getSystemResourceAsStream,所以推薦直接使用getResourceAsStream就完事了都不需要知道具體兩者有啥區別。

下面我們來細看有啥區別....

3.1 java類加載器

  • 1.啟動類加載器Bootstrap ClassLoader):頂層的類加載器,沒有父類加載器。負責加載 /lib 目錄下的,或被 -Xbootclasspath 參數所指定路徑中的,並被 JVM 識別的(僅按文件名識別,如 rt.jar,名字不符合的類庫即使放在 lib 目錄也不會被加載)類庫加載到虛擬機內存中。所有被 Bootstrap classloader 加載的類,它的 Class.getClassLoader 方法返回的都是 null,所以也稱作 NULL ClassLoader。
  • 2.擴展類加載器Extension CLassLoader):由 sun.misc.Launcher$ExtClassLoader 實現,負責加載 <JAVA_HOME>/lib/ext 目錄下,或被 java.ext.dirs 系統變量所指定的目錄下的所有類庫;
  • 3.應用程序類加載器Application/System ClassLoader):由 sun.misc.Launcher$AppClassLoader 實現。它是 ClassLoader.getSystemClassLoader() 方法的默認返回值,所以也稱為系統類加載器(System ClassLoader)。它負責加載 classpath 下所指定的類庫,如果應用程序沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

3.2 tomcat容器下類加載器

Tomcat官方說明:Class Loader HOW-TO

跟普通的java程序相比,類加載大體順序相同。

  • 1.Bootstrap 啟動類加載器: 加載JVM啟動所需的類+系統擴展目錄($JAVA_HOME/jre/lib/ext)里 JAR 文件中的類。
  • 2.System 系統類加載器:從 CLASSPATH 系統變量指定的目錄中加載類庫。該加載器加載的類對 tomcat 本身和 web 應用都可見。但是,標准的 tomcat 啟動腳本($CATALINA_HOME/bin/catalina.sh or %CATALINA_HOME%\bin\catalina.bat)都會忽略系統變量 CLASSPATH 的值,而會使用如下的類庫來創建 System 類加載器:

          $CATALINA_HOME/bin/bootstrap.jar

        $CATALINA_BASE/bin/tomcat-juli.jar 或 $CATALINA_HOME/bin/tomcat-juli.jar

        $CATALINA_HOME/bin/commons-daemon.jar

  • 3.Common 通用類加載器:通過該類加載器加載的類庫可被 Tomcat 和所有應用共享。該類加載器的搜索位置是通過 $CATALINA_BASE/conf/catalina.properties 文件中的 common.loader 屬性指定的,默認包括如下位置:

        $CATALINA_BASE/lib 下未打包的類和資源;

        $CATALINA_BASE/lib 下的 jar 包;

        $CATALINA_HOME/lib 下未打包的類和資源;

        $CATALINA_HOME/lib 下的 jar 包。

  • 4.WebappX 應用類加載器:每個 Web 應用創建一個自己的類加載器,加載自己項目下的數據: /WEB-INF/classes 和 /WEB-INF/lib 下的類和資源。並且不使用雙親委派機制,先自己加載,加載不到才使用父類加載器。

本來順序是1234,但是WebappX不使用委派機制而是先自己加載,加載不了才使用父類,所以真實的順序是:

  • Bootstrap classes of your JVM
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • System class loader classes (described above)
  • Common class loader classes (described above)

tomcat8支持委托:配置允許委派:<Loader delegate="true"/>,順序變為:

  • Bootstrap classes of your JVM
  • System class loader classes (described above)
  • Common class loader classes (described above)
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application

3.3 問題回歸

tomcat容器中運行的java程序,使用系統類加載器是不能獲取到資源的,必須使用WebappClassLoader。使用getResourceAsStream獲取當前類的類加載器,也就是WebappClassLoader,自然可以獲取到資源了。


=======參考=========

https://blog.csdn.net/w1196726224/article/details/54428493

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM