Java中用ClassLoader载入各种资源(类、文件、web资源)的方法
ClassLoader主要對類的請求提供服務,當JVM需要某類時,它根據名稱向ClassLoader要求這個類,然后由ClassLoader返回這個類的class對象。
ClassLoader負責載入系統的所有資源(Class,文件,圖片,來自網絡的字節流等),通過ClassLoader從而將資源載入JVM 中。每個class都有一個引用,指向自己的ClassLoader。
1. 獲得ClassLoader的幾種方法
可以通過如下3種方法得到ClassLoader :
this.getClass.getClassLoader(); ?// 使用當前類的ClassLoader?
?
Thread.currentThread().getContextClassLoader(); ?// 使用當前線程的ClassLoader?
?
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??
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種方式,前兩種方式完全是多余。
實則不然,直接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流讀取?
/**
?* 假設當前位置是 "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
————————————————
版權聲明:本文為CSDN博主「小敏紙」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lanxuezaipiao/article/details/19412025
總結
以上是生活随笔為你收集整理的Java中用ClassLoader载入各种资源(类、文件、web资源)的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tomcat8源码编译及导入Eclips
- 下一篇: Google Java编程风格指南中文版