ClassLoader 初步

與普通程序不一樣的是,Java程序(class文件)並非本地的可執行程序。當運行Java程序時,首先運行JVM(Java虛擬機),而後再把 Java class加載到JVM裏頭運行,負責加載Java class的這部分就叫作Class Loader。   JVM自己包含了一個ClassLoader稱爲Bootstrap ClassLoader,和JVM同樣,BootstrapClassLoader是用本地代碼實現的,它負責加載核心JavaClass(即全部 java.*開頭的類)。另外JVM還會提供兩個ClassLoader,它們都是用Java語言編寫的,由BootstrapClassLoader加 載;其中Extension ClassLoader負責加載擴展的Javaclass(例如全部javax.*開頭的類和存放在JRE的ext目錄下的 類),ApplicationClassLoader負責加載應用程序自身的類。   當運行一個程序的時候,JVM啓動,運行bootstrapclassloader,該 ClassLoader加載java核心API(ExtClassLoader和AppClassLoader也在此時被加載),而後調用 ExtClassLoader加載擴展API,最後AppClassLoader加載CLASSPATH目錄下定義的Class,這就是一個程序最基本的 加載流程。   注: 學ClassLoader看OSGIjava

何時加載類?

   何時JVM會使用ClassLoader加載一個類呢?當你使用java去執行一個類,JVM使用ApplicationClassLoader加 載這個類;而後若是類A引用了類B,不論是直接引用仍是用Class.forName()引用,JVM就會找到加載類A的ClassLoader,並用這 個ClassLoader來加載類B。JVM按照運行時的有效執行語句,來決定是否須要裝載新類,從而裝載儘量少的類,這一點和編譯類是不相同的。   Why use your own ClassLoader?   彷佛JVM自身的ClassLoader已經足夠了,爲何咱們還須要建立本身的ClassLoader呢?   由於JVM自帶的ClassLoader只是懂得從本地文件系統加載標準的java class文件,若是編寫你本身的ClassLoader,你能夠作到:   1)在執行非置信代碼以前,自動驗證數字簽名   2)動態地建立符合用戶特定須要的定製化構建類   3)從特定的場所取得java class,例如數據庫中   4) 等等   事實上當使用Applet的時候,就用到了特定的ClassLoader,由於這時須要從網絡上加載java class,而且要檢查相關的安全信息。   目前的應用服務器大都使用了ClassLoader技術,即便你不須要建立本身的ClassLoader,瞭解其原理也有助於更好地部署本身的應用。web

類加載器的樹狀結構 & 委託代理模式

   當你決定建立你本身的ClassLoader時,須要繼承java.lang.ClassLoader或者它的子類。在實例化每一個 ClassLoader對象時,須要指定一個父對象;若是沒有指定的話,系統自動指定 ClassLoader.getSystemClassLoader()爲父對象。   因此當建立本身的Class Loader時,只須要重載findClass()這個方法。數據庫

卸載? 重載?

   當一個javaclass被加載到JVM以後,它有沒有可能被卸載呢?咱們知道Win32有FreeLibrary()函數,Posix有 dlclose()函數能夠被調用來卸載指定的動態鏈接庫,可是Java並無提供一個UnloadClass()的方法來卸載指定的類。   在Java中,java class的卸載僅僅是一種對系統的優化,有助於減小應用對內存的佔用。既然是一種優化方法,那麼就徹底是JVM自行決定如何實現,對Java開發人員來 說是徹底透明的。   在何時一個java class/interface會被卸載呢?Sun公司的原話是這麼說的:"class or interfacemay be unloaded if and only if its class loader is unreachable. Classesloaded by the bootstrap loader may not be unloaded."   事實上咱們關心的不是如何卸載類的,咱們關心的是如何更新已經被加載了的類從而更新應用的功能。JSP則是一個很是典型的例子,若是一個JSP文件被 更改了,應用服務器則須要把更改後的JSP從新編譯,而後加載新生成的類來響應後繼的請求。   其實一個已經加載的類是沒法被更新的,若是你試圖用同一個ClassLoader再次加載同一 個類,就會獲得異常(java.lang.LinkageError: duplicate classdefinition),咱們只可以從新建立一個新的ClassLoader實例來再次加載新類。至於原來已經加載的類,開發人員沒必要去管它, 由於它可能還有實例正在被使用,只要相關的實例都被內存回收了,那麼JVM就會在適當的時候把不會再使用的類卸載。   使用線程上下文類加載器, 能夠在執行線程中, 拋棄雙親委派加載鏈模式, 使用線程上下文裏的類加載器加載類.   典型的例子有, 經過線程上下文來加載第三方庫jndi實現, 而不依賴於雙親委派.   大部分java app服務器(jboss, tomcat..)也是採用contextClassLoader來處理web服務。   固然, 好東西都有利弊. 使用線程上下文加載類, 也要注意, 保證多根鬚要通訊的線程間的類加載器應該是同一個, 防止由於不一樣的類加載器, 致使類型轉換異常(ClassCastException).bootstrap

相關文章
相關標籤/搜索