Java中用ClassLoader載入各種資源(類、檔案、web資源)的方法

來源:互聯網
上載者:User

標籤:出現   第一步   io流   變數   假設   位元組流   捆綁   需要   根據   

lassLoader主要對類的請求提供服務,當JVM需要某類時,它根據名稱向ClassLoader要求這個類,然後由ClassLoader返回這個類的class對象。

ClassLoader負責載入系統的所有資源(Class,檔案,圖片,來自網路的位元組流等),通過ClassLoader從而將資源載入JVM 中。每個class都有一個引用,指向自己的ClassLoader。

 

1. 獲得ClassLoader的幾種方法

可以通過如下3種方法得到ClassLoader :


 
  1. this.getClass.getClassLoader();  // 使用當前類的ClassLoader   
  2.   
  3. Thread.currentThread().getContextClassLoader();  // 使用當前線程的ClassLoader   
  4.   
  5. ClassLoader.getSystemClassLoader();  // 使用系統ClassLoader,即系統的進入點所使用的ClassLoader。  

 

註:system ClassLoader與根ClassLoader並不一樣。JVM下system ClassLoader通常為App ClassLoader。

 

2. 用ClassLoader載入資源的幾種方法 

所有資源都通過ClassLoader載入到JVM裡,那麼在載入資源時當然可以使用ClassLoader,只是對於不同的資源還可以使用一些別的方式載入,例如對於類可以直接new,對於檔案可以直接做IO等。

 

2.1 類的載入方式

假設有類A和類B,A在其方法裡需要執行個體化B,載入類可能的方法有3種。對於載入類的情況,使用者需要知道B類的完整名字(包括包名,例如"com.alexia.B") 

1. 使用Class靜態方法 Class.forName  

 


 
  1. Class cls = Class.forName("com.alexia.B");  
  2.  B b = (B)cls.newInstance();  

 

2. 使用ClassLoader  

 


 
  1. /* Step 1. Get ClassLoader */  
  2. ClassLoader cl = this.getClass.getClassLoader();;  // 如何獲得ClassLoader參考1  
  3.   
  4. /* Step 2. Load the class */  
  5. Class cls = cl.loadClass("com.alexia.B"); // 使用第一步得到的ClassLoader來載入B  
  6.      
  7. /* Step 3. new instance */  
  8. B b = (B)cls.newInstance(); // 有B的類得到一個B的執行個體  

 

3. 直接new 

 


 
  1. B b = new B();  

 

註:有人心裡可能會想,對於類的載入方式我們都會選擇最簡單的第3種方式,前兩種方式完全是多餘。

實則不然,直接new的方式也是有局限的,舉個最簡單的例子:Java中有包名的類怎麼引用預設包中的類?當然說這個是因為有包名的類不能直接用new引用預設包中的類,那麼怎麼辦呢?答案是使用反射機制,即使用第一種方式來載入類(具體請看這裡)。而且,用new()和用newInstance()建立類的執行個體是不同的,主要區別簡單描述如下:

從JVM的角度看,我們使用關鍵字new建立一個類的時候,這個類可以沒有被載入。但是使用newInstance()方法的時候,就必須保證:

(1)這個類已經載入;

(2)這個類已經連結了(即為靜態域分配儲存空間,並且如果必須的話將解析這個類建立的對其他類的所有引用)。而完成上面兩個步驟的正是Class的靜態方法forName()所完成的,這個靜態方法調用了啟動類載入器,即載入javaAPI的那個載入器。

可以看出,newInstance()實際上是把new這個方式分解為兩步,即首先調用Class載入方法載入某個類,然後執行個體化。這樣分步的好處是顯而易見的。我們可以在調用class的靜態載入方法forName時獲得更好的靈活性,提供給了一種降耦的手段。

 

2.2 檔案的載入方式(例如設定檔等)

假設在com.alexia.A類裡想讀取檔案夾 /com/alexia/config 裡的檔案sys.properties,讀取檔案可以通過絕對路徑或相對路徑,絕對路徑很簡單,在Windows下以盤號開始,在Unix下以"/"開始。對於相對路徑,其相對值是相對於ClassLoader的,因為ClassLoader是一棵樹,所以這個相對路徑和ClassLoader樹上的任何一個ClassLoader相對比較後可以找到檔案,那麼檔案就可以找到。檔案有以下三種載入方式:

1. 直接用IO流讀取 

 


 
  1. /** 
  2.  * 假設當前位置是 "C:/test",通過執行如下命令來運行A "java com.aleixa.A" 
  3.  * 1. 在程式裡可以使用絕對路徑,Windows下的絕對路徑以盤號開始,Unix下以"/"開始 
  4.  * 2. 也可以使用相對路徑,相對路徑前面沒有"/" 
  5.  * 因為我們在 "C:/test" 目錄下執行程式,程式進入點是"C:/test",相對路徑就 
  6.  * 是 "com/alexia/config/sys.properties" 
  7.  * (例子中,當前程式的ClassLoader是App ClassLoader,system ClassLoader = 當前的 
  8.  * 程式的ClassLoader,進入點是"C:/test") 
  9.  * 對於ClassLoader樹,如果檔案在jdk lib下,或在jdk lib/ext下,或在環境變數裡, 
  10.  * 都可以通過相對路徑"sys.properties"找到,lib下的檔案最先被找到 
  11.  */  
  12. File f = new File("C:/test/com/aleixa/config/sys.properties"); // 使用絕對路徑  
  13. //File f = new File("com/alexia/config/sys.properties"); // 使用相對路徑  
  14. InputStream is = new FileInputStream(f);    

 

2. 使用ClassLoader  

 


 
  1. /** 
  2.  * 因為有3種方法得到ClassLoader,對應有如下3種ClassLoader方法讀取檔案 
  3.  * 使用的路徑是相對於這個ClassLoader的那個點的相對路徑,此處只能使用相對路徑 
  4.  */  
  5. InputStream is = null;  
  6. is = this.getClass().getClassLoader().getResourceAsStream(  
  7.        "com/alexia/config/sys.properties"); //方法1  
  8. //is = Thread.currentThread().getContextClassLoader().getResourceAsStream(  
  9.        "com/alexia/config/sys.properties"); //方法2  
  10. //is = ClassLoader.getSystemResourceAsStream("com/alexia/config/sys.properties"); //方法3   

 

3. 使用ResourceBundle 

 


 
  1. ResourceBundle bundle = ResourceBundle.getBoundle("com.alexia.config.sys");   

 

這種用法通常用來載入使用者的設定檔,關於ResourceBunlde更詳細的用法請參考其他文檔。

註:如果是屬性設定檔,也可以通過java.util.Properties.load(is)將內容讀到Properties裡,Properties預設認為is的編碼是ISO-8859-1,如果設定檔是非英文的,可能出現亂碼問題。

 

總結:有如下3種途徑來載入檔案 

    1. 絕對路徑 ---> IO
    2. 相對路徑 ---> IO 
                      ---> ClassLoader 
    3. 資源捆綁 ---> ResourceBundle 

 

2.3 web資源的載入方式

在web應用裡當然也可以使用ClassLoader來載入資源,但更常用的情況是使用ServletContext,如下是web目錄結構 
    ContextRoot 
       |- JSP、HTML、Image等各種檔案 
        |- [WEB-INF] 
              |- web.xml 
              |- [lib] Web用到的JAR檔案 
                |- [classes] 類檔案 

使用者程式通常在classes目錄下,如果想讀取classes目錄裡的檔案,可以使用ClassLoader,如果想讀取其他的檔案,一般使用ServletContext.getResource()。

如果使用ServletContext.getResource(path)方法,路徑必須以"/"開始,路徑被解釋成相對於ContextRoot的路徑,此處載入檔案的方法和ClassLoader不同,舉例"/WEB-INF/web.xml","/download/WebExAgent.rar"

Java中用ClassLoader載入各種資源(類、檔案、web資源)的方法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.