日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ClassLoader 详解及用途

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ClassLoader 详解及用途 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自?ClassLoader 詳解及用途

?

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

1.1?幾個相關概念ClassLoader負責載入系統的所有Resources(Class,文件,來自網絡的字節流等),通過ClassLoader從而將資源載入JVM??

每個class都有一個reference,指向自己的ClassLoader。Class.getClassLoader()??

?

array的ClassLoader就是其元素的ClassLoader,若是基本數據類型,則這個array沒有ClassLoader?

?

?

1.2?主要方法和工作過程Java1.1及從前版本中,ClassLoader主要方法:??

Class?loadClass(?String?name,?boolean?resolve?);?ClassLoader.loadClass()?是?ClassLoader?的入口點??
defineClass?方法是?ClassLoader?的主要訣竅。該方法接受由原始字節組成的數組并把它轉換成?Class?對象。原始數組包含如從文件系統或網絡裝入的數據。??
findSystemClass?方法從本地文件系統裝入文件。它在本地文件系統中尋找類文件,如果存在,就使用?defineClass?將原始字節轉換成?Class?對象,以將該文件轉換成類。當運行?Java?應用程序時,這是?JVM?正常裝入類的缺省機制。??
resolveClass可以不完全地(不帶解析)裝入類,也可以完全地(帶解析)裝入類。當編寫我們自己的?loadClass?時,可以調用?resolveClass,這取決于?loadClass?的?resolve?參數的值??
findLoadedClass?充當一個緩存:當請求?loadClass?裝入類時,它調用該方法來查看?ClassLoader?是否已裝入這個類,這樣可以避免重新裝入已存在類所造成的麻煩。應首先調用該方法??
一般load方法過程如下:??

調用?findLoadedClass?來查看是否存在已裝入的類。??
如果沒有,那么采用某種特殊的神奇方式來獲取原始字節。(通過IO從文件系統,來自網絡的字節流等)??
如果已有原始字節,調用?defineClass?將它們轉換成?Class?對象。??
如果沒有原始字節,然后調用?findSystemClass?查看是否從本地文件系統獲取類。??
如果?resolve?參數是?true,那么調用?resolveClass?解析?Class?對象。??
如果還沒有類,返回?ClassNotFoundException。??
否則,將類返回給調用程序。??

?

?

?

1.3?委托模型自從JDK1.2以后,ClassLoader做了改進,使用了委托模型,所有系統中的ClassLoader組成一棵樹,ClassLoader在載入類庫時先讓Parent尋找,Parent找不到才自己找。??

JVM在運行時會產生三個ClassLoader,Bootstrap?ClassLoader、Extension?ClassLoader和App?ClassLoader。其中,Bootstrap?ClassLoader是用C++編寫的,在Java中看不到它,是null。它用來加載核心類庫,就是在lib下的類庫,Extension?ClassLoader加載lib/ext下的類庫,App?ClassLoader加載Classpath里的類庫,三者的關系為:App?ClassLoader的Parent是Extension?ClassLoader,而Extension?ClassLoader的Parent為Bootstrap?ClassLoader。加載一個類時,首先BootStrap進行尋找,找不到再由Extension?ClassLoader尋找,最后才是App?ClassLoader。??

將ClassLoader設計成委托模型的一個重要原因是出于安全考慮,比如在Applet中,如果編寫了一個java.lang.String類并具有破壞性。假如不采用這種委托機制,就會將這個具有破壞性的String加載到了用戶機器上,導致破壞用戶安全。但采用這種委托機制則不會出現這種情況。因為要加載java.lang.String類時,系統最終會由Bootstrap進行加載,這個具有破壞性的String永遠沒有機會加載。??

委托模型還帶來了一些問題,在某些情況下會產生混淆,如下是Tomcat的ClassLoader結構圖:??

????????????????Bootstrap?
??????????????????|?
????????????????System?
??????????????????|?
????????????????Common?
????????????????/?????
????????????Catalina??Shared?
??????????????????????/?????
???????????????????Webapp1??Webapp2?...?

由?Common?類裝入器裝入的類決不能(根據名稱)直接訪問由?Web?應用程序裝入的類。使這些類聯系在一起的唯一方法是通過使用這兩個類集都可見的接口。在這個例子中,就是包含由?Java?servlet?實現的?javax.servlet.Servlet。??
如果在lib或者lib/ext等類庫有與應用中同樣的類,那么應用中的類將無法被載入。通常在jdk新版本出現有類庫移動時會出現問題,例如最初我們使用自己的xml解析器,而在jdk1.4中xml解析器變成標準類庫,load的優先級也高于我們自己的xml解析器,我們自己的xml解析器永遠無法找到,將可能導致我們的應用無法運行。??

相同的類,不同的ClassLoader,將導致ClassCastException異常??

1.4?線程中的ClassLoader每個運行中的線程都有一個成員contextClassLoader,用來在運行時動態地載入其它類,可以使用方法Thread.currentThread().setContextClassLoader(...);更改當前線程的contextClassLoader,來改變其載入類的行為;也可以通過方法Thread.currentThread().getContextClassLoader()來獲得當前線程的ClassLoader。??
實際上,在Java應用中所有程序都運行在線程里,如果在程序中沒有手工設置過ClassLoader,對于一般的java類如下兩種方法獲得的ClassLoader通常都是同一個??

this.getClass.getClassLoader();??
Thread.currentThread().getContextClassLoader();??
方法一得到的Classloader是靜態的,表明類的載入者是誰;方法二得到的Classloader是動態的,誰執行(某個線程),就是那個執行者的Classloader。對于單例模式的類,靜態類等,載入一次后,這個實例會被很多程序(線程)調用,對于這些類,載入的Classloader和執行線程的Classloader通常都不同。??

1.5?Web應用中的ClassLoader回到上面的例子,在Tomcat里,WebApp的ClassLoader的工作原理有點不同,它先試圖自己載入類(在ContextPath/WEB-INF/...中載入類),如果無法載入,再請求父ClassLoader完成。??
由此可得:??

對于WEB?APP線程,它的contextClassLoader是WebAppClassLoader??
對于Tomcat?Server線程,它的contextClassLoader是CatalinaClassLoader??

?

?

?

1.6?獲得ClassLoader的幾種方法可以通過如下3種方法得到ClassLoader??

this.getClass.getClassLoader();?//?使用當前類的ClassLoader??
Thread.currentThread().getContextClassLoader();?//?使用當前線程的ClassLoader??
ClassLoader.getSystemClassLoader();?//?使用系統ClassLoader,即系統的入口點所使用的ClassLoader。(注意,system?ClassLoader與根ClassLoader并不一樣。JVM下system?ClassLoader通常為App?ClassLoader)??

?

?

?

1.7?幾種擴展應用用戶定制自己的ClassLoader可以實現以下的一些應用??

安全性。類進入JVM之前先經過ClassLoader,所以可以在這邊檢查是否有正確的數字簽名等??
加密。java字節碼很容易被反編譯,通過定制ClassLoader使得字節碼先加密防止別人下載后反編譯,這里的ClassLoader相當于一個動態的解碼器??
歸檔。可能為了節省網絡資源,對自己的代碼做一些特殊的歸檔,然后用定制的ClassLoader來解檔??
自展開程序。把java應用程序編譯成單個可執行類文件,這個文件包含壓縮的和加密的類文件數據,同時有一個固定的ClassLoader,當程序運行時它在內存中完全自行解開,無需先安裝??
動態生成。可以生成應用其他還未生成類的類,實時創建整個類并可在任何時刻引入JVM??

?

?

?

2.1?資源載入?

所有資源都通過ClassLoader載入到JVM里,那么在載入資源時當然可以使用ClassLoader,只是對于不同的資源還可以使用一些別的方式載入,例如對于類可以直接new,對于文件可以直接做IO等。?2.1?載入類的幾種方法假設有類A和類B,A在方法amethod里需要實例化B,可能的方法有3種。對于載入類的情況,用戶需要知道B類的完整名字(包括包名,例如"com.rain.B")??

?

?

?

2.1.1 使用Class靜態方法?Class.forName??


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

2.1.2 使用ClassLoader??
????/*?Step?1.?Get?ClassLoader?*/?
????ClassLoader?cl;?//?如何獲得ClassLoader參考1.6?

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

?

2.1.3 直接new??

????B?b?=?new?B();?

?

?

?

?

?

2.2?文件載入(例如配置文件等)假設在com.rain.A類里想讀取文件夾?/com/rain/config?里的文件sys.properties,讀取文件可以通過絕對路徑或相對路徑,絕對路徑很簡單,在Windows下以盤號開始,在Unix下以"/"開始??

對于相對路徑,其相對值是相對于ClassLoader的,因為ClassLoader是一棵樹,所以這個相對路徑和ClassLoader樹上的任何一個ClassLoader相對比較后可以找到文件,那么文件就可以找到,當然,讀取文件也使用委托模型??

2.2.1 直接IO??

/** * 假設當前位置是 "C:/test",通過執行如下命令來運行A "java com.rain.A" * 1. 在程序里可以使用絕對路徑,Windows下的絕對路徑以盤號開始,Unix下以"/"開始 * 2. 也可以使用相對路徑,相對路徑前面沒有"/" * 因為我們在 "C:/test" 目錄下執行程序,程序入口點是"C:/test",相對路徑就 * 是 "com/rain/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/rain/config/sys.properties"); // 使用絕對路徑 //File f = new File("com/rain/config/sys.properties"); // 使用相對路徑 InputStream is = new FileInputStream(f);

如果是配置文件,可以通過java.util.Properties.load(is)將內容讀到Properties里,Properties默認認為is的編碼是ISO-8859-1,如果配置文件是非英文的,可能出現亂碼問題。??

?

?

?

2.2.2 使用ClassLoader??

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

如果是配置文件,可以通過java.util.Properties.load(is)將內容讀到Properties里,這里要注意編碼問題。??

?

?

?

2.2.3 使用ResourceBundle??

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

這種用法通常用來載入用戶的配置文件,關于ResourceBunlde更詳細的用法請參考其他文檔??
總結:有如下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"

總結

以上是生活随笔為你收集整理的ClassLoader 详解及用途的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。