Java加載資源文件時的路徑問題


今天偶然看到一篇關於tomcat加載servlet的文章,不由得想起了java加載資源文件的路徑問題,資源文件可以使xml,properties,圖片等,可以是任何文件。

加載資源文件比較常用的有兩種:

一、用ClassLoader,說到這里就不得不提一下ClassLoader的分類,java內置的ClassLoader主要有三種,

第一種是根類加載器(bootstrap class loader),用C++來編寫,負責將一些關鍵的Java類,如java.lang.Object和其他一些運行時代碼先加載進內存中。 所負責加載的包:BootStrp------>JRE/lib/rt.jar

第二種是擴展類加載器(ExtClassLoader),由java類編寫,負責將JRE中的一些類加載進內存中。所負責加載的包: ExtClassLoader---------->JRE/lib/ext/*.jar

第三種是應用類加載器(AppClassLoader)或者叫做系統類加載器,負責將CLASSPATH中的類加載到內存中。可以通過ClassLoader.getSystemClassLoader()來獲取應用類加載器;

 

再來所說加類載器的繼承,類加載器不是垂直繼承的父子關系,而是一種組合關系,可以通過實例化類加載器時,將父類加載器的實例作為構造參數傳到類加載器中。

關於類加載器的詳細資料,可以自行搜索。

 

獲取到應用類加載器之后,就是獲取資源文件了,調用loader.getResource(path)可以加載相應路徑下的資源文件,不能以‘/’開頭,關於包內的資源可以把包當做普通的文件夾,以'/'分隔每個包。

如:URL url2 =  ClassLoader.getSystemClassLoader().getResource("demo/names.ser");是獲取demo包內的names.ser序列化文件。

二、用需要加載的當前類的getResource方法來加載,其實這個方法也是調用的加載這個類的類加載器來獲得資源文件的,只不過是獲取的參數不同。

 (1)要想獲取class所在包內的文件可以用相對路徑直接訪問包內的資源;如:Demo1.class.getResource("names.ser");獲取的是Demo1的class文件所在包內的資源

 (2)要想獲取包外的資源文件必須以‘/’開頭,如URL url = Demo1.class.getResource("/demo/names.ser");獲取的是demo包內的names.ser文件

 

其實第二種方式是對第一種方式的一個封裝,都是用的ClassLoader來加載的資源文件。為什么這么說呢?看一下Class類的源碼就知道:

 

1  public java.net.URL getResource(String name) {
2         name = resolveName(name);
3         ClassLoader cl = getClassLoader0();
4         if (cl==null) {
5             // A system class.
6             return ClassLoader.getSystemResource(name);
7         }
8         return cl.getResource(name);
9     }

 

 1  private String resolveName(String name) {
 2         if (name == null) {
 3             return name;
 4         }
 5         if (!name.startsWith("/")) {
 6             Class c = this;
 7             while (c.isArray()) {
 8                 c = c.getComponentType();
 9             }
10             String baseName = c.getName();
11             int index = baseName.lastIndexOf('.');
12             if (index != -1) {
13                 name = baseName.substring(0, index).replace('.', '/')
14                     +"/"+name;
15             }
16         } else {
17             name = name.substring(1);
18         }
19         return name;
20     }

getResource根據傳進來的name值(即相對路徑或者絕對路徑的形式),我們看到經過resolveName處理之后就調用了ClassLoader c1進行了加載,ClassLoader的加載路徑的形式是不以‘/’開頭的相對路徑,那肯定是resolveName把路徑轉換了一把,再看看resolveName方法,首先判斷是不是以‘/’開頭,如果以‘/’開頭,則為相對路徑,否則就是絕對路徑,注意else這個代碼塊,它將第一個字符去除掉了,確實去除掉之后就符合了ClassLoader的加載路徑,而if塊中就根據把當前類的包路徑截取,然后將.替換成了'/',並添加上那段相對路徑,也形成了符合ClassLoader的加載路徑。

 

看了這些代碼之后,才能在實際應用中心里有底啊。


免責聲明!

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



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