日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
JavaClassLoader?

1. ClassLoader

類加載器(class loader)用來加載 Java 類到 Java 虛擬機中。Java 源程序(.java 文件)在經(jīng)過 Java 編譯器編譯之后就被轉(zhuǎn)換成 Java 字節(jié)代碼(.class 文件)。類加載器負責(zé)讀取 Java 字節(jié)代碼,并轉(zhuǎn)換成 java.lang.Class 類的一個實例。

2. ClassLoader Hierarchy

JVM在加載類時,使用的是雙親委托模式(delegation model),也就是說除了Bootstrap ClassLoader之外,每個ClassLoader都有一個Parent ClassLoader。ClassLoader是按需進行加載class文件。當(dāng)ClassLoader試圖加載一個類時,首先檢查本地緩沖,查看類是否已被加載,如果類沒有被加載,嘗試委托給父ClassLoader進行加載,如果父ClassLoader加載失敗,才會由該ClassLoader進行加載,從而避免了重復(fù)加載的問題。一下為類裝載器層次圖:

Bootstrap ClassLoader:負責(zé)加載java_home/lib目錄下的核心類或- Xbootclasspath指定目錄下的類。

Extension ClassLoader:負責(zé)加載java_home/lib/ext目錄下的擴展類或 -Djava.ext.dirs 指定目錄下的類。

System ClassLoader:負責(zé)加載-classpath/-Djava.class.path所指的目錄下的類。

如果類App1在本地緩沖中沒有class文件(沒有被加載),那么它會自底向上依次查找是否已經(jīng)加載了類,如果已經(jīng)加載,則直接返回該類實例的引用。如果BootstrapClassLoader也未成功加載該類,那么會拋出異常,然后自頂向下依次嘗試加載,如果到App1 ClassLoader還沒有加載成功,那么會拋出ClassNotFoundException異常給調(diào)用者。

Java代碼

 
 
 
 
  1. public static void main(String[] args) {     
  2.         ClassLoader cl = ClassLoader.getSystemClassLoader();     
  3.         while(cl != null){     
  4.             System.out.println(cl);     
  5.             System.out.println("parent class loader: " + cl.getParent());     
  6.             cl = cl.getParent();     
  7.         }     
  8.     }  

Java代碼

 
 
 
 
  1. sun.misc.Launcher$AppClassLoader@19821f    
  2. parent class loader: sun.misc.Launcher$ExtClassLoader@addbf1    
  3. sun.misc.Launcher$ExtClassLoader@addbf1    
  4. parent class loader: null   

我們看到,當(dāng)前系統(tǒng)類裝載器為AppClassLoader,AppClassLoader的父類裝載器是ExtClassLoader,ExtClassLoader的父裝載器為null,表示為BootstrapClassLoader。BootstrapClassLoader由JVM采用本地代碼實現(xiàn),因此沒有對應(yīng)的Java類,所以ExtClassLoader的getParent()返回null。

ClassLoader的職責(zé)之一是保護系統(tǒng)名字空間。以下為ClassLoader類部分代碼:

Java代碼

 
 
 
 
  1. private ProtectionDomain preDefineClass(String name,     
  2.                         ProtectionDomain protectionDomain)     
  3.     {     
  4.     if (!checkName(name))     
  5.         throw new NoClassDefFoundError("IllegalName: " + name);     
  6.     
  7.     if ((name != null) && name.startsWith("java.")) {     
  8.         throw new SecurityException("Prohibited package name: " +     
  9.                     name.substring(0, name.lastIndexOf('.')));     
  10.     }     
  11.     if (protectionDomain == null) {     
  12.         protectionDomain = getDefaultDomain();     
  13.     }     
  14.     
  15.     if (name != null)     
  16.         checkCerts(name, protectionDomain.getCodeSource());     
  17.     
  18.     return protectionDomain;     
  19.     } 

那么,當(dāng)我們定義如下類Foo,雖然能夠通過編譯,但是會報java.lang.SecurityException: Prohibited package name: java.lang異常,因為我們試圖將Foo類寫入到j(luò)ava.lang包下。

Java代碼

 
 
 
 
  1. package java.lang;     
  2.     
  3. public class Foo {     
  4.          
  5.     public static void main(String args[]) throws Exception {     
  6.         Foo f = new Foo();     
  7.         System.out.println(f.toString());     
  8.     }     
  9. }   

3. 定制ClassLoader

Java自帶的ClassLoader類的定義為:

Java代碼

 
 
 
 
  1. public abstract class ClassLoader{      

啟動類加載器是JVM通過調(diào)用ClassLoader.loadClass()方法。

Java代碼

 
 
 
 
  1. public Class  loadClass(String name) throws ClassNotFoundException {     
  2.     return loadClass(name, false);     
  3.     }     
  4.     
  5. protected synchronized Class  loadClass(String name, boolean resolve)     
  6.     throws ClassNotFoundException     
  7.     {     
  8.     // First, check if the class has already been loaded     
  9.     Class c = findLoadedClass(name);     
  10.     if (c == null) {     
  11.         try {     
  12.         if (parent != null) {     
  13.             c = parent.loadClass(name, false);     
  14.         } else {     
  15.             c = findBootstrapClass0(name);     
  16.         }     
  17.         } catch (ClassNotFoundException e) {     
  18.             // If still not found, then invoke findClass in order     
  19.             // to find the class.     
  20.             c = findClass(name);     
  21.         }     
  22.     }     
  23.     if (resolve) {     
  24.         resolveClass(c);     
  25.     }     
  26.     return c;     
  27.     }     
  28.     
  29. protected Class  findClass(String name) throws ClassNotFoundException {     
  30.     throw new ClassNotFoundException(name);     
  31.     }    

loadClass(String name, boolean resolve)方法中的resolve如果為true,表示分析這個Class對象,包括檢查Class Loader是否已經(jīng)初始化等。loadClass(String name) 在加載類之后不會對該類進行初始化,直到***次使用該類時,才會對該類進行初始化。

那么,我們在定制ClassLoader的時候,通常只需要覆寫findClass(String name)方法。在findClass(String name)方法內(nèi),我們可以通過文件、網(wǎng)絡(luò)(URL)等形式獲取字節(jié)碼。以下為獲取字節(jié)碼的方法:

Java代碼

 
 
 
 
  1. public InputStream getResourceAsStream(String name);     
  2. public URL getResource(String name);     
  3. public InputStream getResourceAsStream(String name);     
  4. public Enumeration  getResources(String name)  throws IOException;   

在取得字節(jié)碼后,需要調(diào)用defineClass()方法將字節(jié)數(shù)組轉(zhuǎn)換成Class對象,該方法簽名如下:

Java代碼

 
 
 
 
  1. protected final Class  defineClass(String name, byte[] b, int off, int len,     
  2.                      ProtectionDomain protectionDomain)     
  3.     throws ClassFormatError  

對于相同的類,JVM最多會載入一次。如果同一個class文件被不同的ClassLoader載入(定義),那么載入后的兩個類是完全不同的。

Java代碼

 
 
 
 
  1. public class Foo{     
  2.     //     
  3.     private static final AtomicInteger COUNTER = new AtomicInteger(0);     
  4.     
  5.     public Foo() {     
  6.         System.out.println("counter: " + COUNTER.incrementAndGet());     
  7.     }     
  8.          
  9.     public static void main(String args[]) throws Exception {     
  10.         URL urls[] = new URL[]{new URL("file:/c:/")};     
  11.         URLClassLoader ucl1 = new URLClassLoader(urls);     
  12.         URLClassLoader ucl2 = new URLClassLoader(urls);     
  13.         Class  c1 = ucl1.loadClass("Foo");     
  14.         Class  c2 = ucl2.loadClass("Foo");     
  15.         System.out.println(c1 == c2);     
  16.         c1.newInstance();     
  17.         c2.newInstance();     
  18.     }     
  19. }   

以上程序需要保證Foo.class文件不在classpath路徑下。從而使AppClassLoader無法加載Foo.class。

輸出結(jié)果:

Java代碼

 
 
 
 
  1. false    
  2. counter: 1    
  3. counter: 1 

4. Web應(yīng)用的ClassLoader

絕大多數(shù)的EJB容器,Servlet容器等都會提供定制的ClassLoader,來實現(xiàn)特定的功能。但是通常情況下,所有的servlet和filter使用一個ClassLoader。每個jsp都使用一個獨立的ClassLoader。

5. 隱式(implicit)和顯示(explicit)的加載

隱式加載:我們使用new關(guān)鍵字實例化一個類,就是隱身的加載了類。

顯示加載分為兩種:

java.lang.Class的forName()方法;

java.lang.ClassLoader的loadClass()方法。

Class.forName()方法有兩個重載的版本:

Java代碼

 
 
 
 
  1. public static Class  forName(String className)      
  2.                 throws ClassNotFoundException {     
  3.         return forName0(className, true, ClassLoader.getCallerClassLoader());     
  4.     }     
  5.     
  6. public static Class  forName(String name, boolean initialize,     
  7.                    ClassLoader loader)     
  8.         throws ClassNotFoundException   

可以看出,forName(String className)默認以true和ClassLoader.getCallerClassLoader()調(diào)用了三參數(shù)的重載方法。ClassLoader.getCallerClassLoader()表示以caller class loader加載類,并會初始化類(即靜態(tài)變量會被初始化,靜態(tài)初始化塊中的代碼也會被執(zhí)行)。如果以false和ClassLoader.getCallerClassLoader()調(diào)用三參數(shù)的重載方法,表示加載后的類不會被初始化。

ClassLoader.loadClass()方法在類加載后,也同樣不會初始化類。

6. 兩個異常(exception)

NoClassDefFoundError: 當(dāng)java源文件已編譯成.class文件,但是ClassLoader在運行期間搜尋路徑load某個類時,沒有找到.class文件則拋出這個異常。

ClassNotFoundException: 試圖通過一個String變量來創(chuàng)建一個Class類時不成功則拋出這個異常


網(wǎng)站欄目:JavaClassLoader?
分享地址:http://www.5511xx.com/article/djdejcj.html