1、類加載器的概念java
類加載器(class loader)用來加載 Java 類到 Java 虛擬機中。通常來講,Java 虛擬機使用 Java 類的方式以下:Java 源程序(.java 文件)在通過 Java 編譯器編譯以後就被轉換成 Java 字節代碼(.class 文件)。類加載器負責讀取 Java 字節代碼到java虛擬機中並轉換成java.lang.Class
類的一個實例。每一個這樣的實例用來表示一個 Java 類。經過此實例的 newInstance()
方法就能夠建立出該類的一個對象。實際的狀況可能更加複雜,好比 Java 字節代碼多是經過工具動態生成的,也多是經過網絡下載的。基本上全部的類加載器都是 java.lang.ClassLoader
類的一個實例。web
2、類加載器的樹狀組織結構bootstrap
Java 中的類加載器大體能夠分紅兩類,一類是系統提供的,另一類則是由 Java 應用開發人員編寫的。緩存
系統提供的類加載器主要有下面三個:安全
java.lang.ClassLoader
。ClassLoader.getSystemClassLoader()
來獲取它。java.lang.ClassLoader
類的方式實現本身的類加載器,以知足一些特殊的需求。除了引導類加載器以外,全部的類加載器都有一個父類加載器。系統類加載器的父類加載器是擴展類加載器,而擴展類加載器的父類加載器是引導類加載器;對於開發人員編寫的類加載器來講,其父類加載器是加載此類加載器 Java 類的類加載器。由於類加載器 Java 類如同其它的 Java 類同樣,也是要由類加載器來加載的。通常來講,開發人員編寫的類加載器的父類加載器是系統類加載器。類加載器經過這種方式組織起來,造成樹狀結構。樹的根節點就是引導類加載器。
每一個 Java 類都維護着一個指向定義它的類加載器的引用,經過 getClassLoader()
方法就能夠獲取到此引用。網絡
Java 虛擬機是如何斷定兩個 Java 類是相同的:Java 虛擬機不只要看類的全名是否相同,還要看加載此類的類加載器是否同樣。只有二者都相同的狀況,才認爲兩個類是相同的。即使是一樣的字節代碼,被不一樣的類加載器加載以後所獲得的類,也是不一樣的。工具
3、加載類的過程url
代理模式:類加載器在嘗試本身去查找某個類的字節代碼並定義它時,會先代理給其父類加載器,由父類加載器先去嘗試加載這個類,依次類推。 真正完成類的加載工做的類加載器和啓動這個加載過程的類加載器,有可能不是同一個。真正完成類的加載工做是經過調用 defineClass
來實現的;而啓動類的加載過程是經過調用 loadClass
來實現的。前者稱爲一個類的定義加載器(defining loader),後者稱爲初始加載器(initiating loader)。在 Java 虛擬機判斷兩個類是否相同的時候,使用的是類的定義加載器。也就是說,哪一個類加載器啓動類的加載過程並不重要,重要的是最終定義這個類的加載器。類加載器在成功加載某個類以後,會把獲得的 java.lang.Class
類的實例緩存起來。下次再請求加載該類的時候,類加載器會直接使用緩存的類的實例,而不會嘗試再次加載。也就是說,對於一個類加載器實例來講,相同全名的類只加載一次,即 loadClass
方法不會被重複調用。spa
4、類加載器與web容器代理
拿Apache Tomcat 來講,每一個 Web 應用都有一個對應的類加載器實例。該類加載器也使用代理模式,所不一樣的是它是首先嚐試去加載某個類,若是找不到再代理給父類加載器。這與通常類加載器的順序是相反的。這是 Java Servlet 規範中的推薦作法,其目的是使得 Web 應用本身的類的優先級高於 Web 容器提供的類。這種代理模式的一個例外是:Java 核心庫的類是不在查找範圍以內的。這也是爲了保證 Java 核心庫的類型安全。