Java中用ClassLoader載入各類資源(類、文件、web資源)的方法

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

ClassLoader負責載入系統的全部資源(Class,文件,圖片,來自網絡的字節流等),java

經過ClassLoader從而將資源載入JVM 中。每一個class都有一個引用,指向本身的ClassLoader。web

1. 得到ClassLoader的幾種方法

能夠經過以下3種方法獲得ClassLoader :網絡

this.getClass.getClassLoader();  // 使用當前類的ClassLoader 

Thread.currentThread().getContextClassLoader();  // 使用當前線程的ClassLoader 

ClassLoader.getSystemClassLoader();  // 使用系統ClassLoader,即系統的入口點所使用的ClassLoader。

注:system ClassLoader與根ClassLoader並不同。JVM下system ClassLoader一般爲App ClassLoader。ui

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

全部資源都經過ClassLoader載入到JVM裏,那麼在載入資源時固然可使用ClassLoader,只是對於不一樣的資源還可使用一些別的方式載入,例如對於類能夠直接new,對於文件能夠直接作IO等。this

2.1 類的載入方式

假設有類A和類B,A在其方法裏須要實例化B,載入類可能的方法有3種。對於載入類的狀況,用戶須要知道B類的完整名字(包括包名,例如"com.alexia.B") 編碼

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

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

2. 使用ClassLoader 

 /* Step 1. Get ClassLoader */
 ClassLoader cl = this.getClass.getClassLoader();;  // 如何得到ClassLoader參考1

 /* Step 2. Load the class */
 Class cls = cl.loadClass("com.alexia.B"); // 使用第一步獲得的ClassLoader來載入B
    
 /* Step 3. new instance */
 B b = (B)cls.newInstance(); // 有B的類獲得一個B的實例

3. 直接new  

B b = new B();

注:有人內心可能會想,對於類的載入方式咱們都會選擇最簡單的第3種方式,前兩種方式徹底是多餘。spa

實則否則,直接new的方式也是有侷限的,舉個最簡單的例子:Java中有包名的類怎麼引用默認包中的類?.net

固然說這個是由於有包名的類不能直接用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流讀取 

/**
 * 假設當前位置是 "C:/test",經過執行以下命令來運行A "java com.aleixa.A"
 * 1. 在程序裏可使用絕對路徑,Windows下的絕對路徑以盤號開始,Unix下以"/"開始
 * 2. 也可使用相對路徑,相對路徑前面沒有"/"
 * 由於咱們在 "C:/test" 目錄下執行程序,程序入口點是"C:/test",相對路徑就
 * 是 "com/alexia/config/sys.properties"
 * (例子中,當前程序的ClassLoader是App ClassLoader,system ClassLoader = 當前的
 * 程序的ClassLoader,入口點是"C:/test")
 * 對於ClassLoader樹,若是文件在jdk lib下,或在jdk lib/ext下,或在環境變量裏,
 * 均可以經過相對路徑"sys.properties"找到,lib下的文件最早被找到
 */
File f = new File("C:/test/com/aleixa/config/sys.properties"); // 使用絕對路徑
//File f = new File("com/alexia/config/sys.properties"); // 使用相對路徑
InputStream is = new FileInputStream(f);  

2. 使用ClassLoader 

/**
 * 由於有3種方法獲得ClassLoader,對應有以下3種ClassLoader方法讀取文件
 * 使用的路徑是相對於這個ClassLoader的那個點的相對路徑,此處只能使用相對路徑
 */
InputStream is = null;
is = this.getClass().getClassLoader().getResourceAsStream(
       "com/alexia/config/sys.properties"); //方法1
//is = Thread.currentThread().getContextClassLoader().getResourceAsStream(
       "com/alexia/config/sys.properties"); //方法2
//is = ClassLoader.getSystemResourceAsStream("com/alexia/config/sys.properties"); //方法3 

3. 使用ResourceBundle 

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"

 

參考:http://blog.chinaunix.net/uid-21227800-id-65885.html

相關文章
相關標籤/搜索