久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

關(guān)于jvm中類加載完全揭密

 昵稱2829056 2010-08-21

        類加載是java語言提供的最強(qiáng)大的機(jī)制之一,。盡管類加載并不是討論的熱點(diǎn)話題,但所有的編程人員都應(yīng)該了解其工作機(jī)制,,明白如何 做才能讓其滿足我們的需要。這能有效節(jié)省我們的編碼時(shí)間,,從不斷調(diào)試ClassNotFoundException, ClassCastException的工作中解脫出來,。

這篇文章從基礎(chǔ)講起,比如代碼與數(shù)據(jù)的不同之處是什么,,他們是如何構(gòu)成一個實(shí)例或?qū)ο蟮?。然后深入探討java虛擬機(jī)(JVM)是如何利用類加載器讀取代 碼,以及java中類加載器的主要類型,。接著用一個類加載的基本算法看一下類加載器如何加載一個內(nèi)部類,。本文的下一節(jié)演示一段代碼來說明擴(kuò)展和開發(fā)屬于自 己的類加載器的必要性。緊接著解釋如何使用定制的類加載器來完成一個一般意義上的任務(wù),,使其可以加載任意遠(yuǎn)端客戶的代碼,,在JVM中定義,實(shí)例化并執(zhí)行 它,。本文包括了J2EE關(guān)于類加載的規(guī)范——事實(shí)上這已經(jīng)成為了J2EE的標(biāo)準(zhǔn)之一,。

類與數(shù)據(jù)

一個類代表要執(zhí)行的代碼,而數(shù)據(jù)則表示其相關(guān)狀態(tài),。狀態(tài)時(shí)常改變,,而代碼則不會。當(dāng)我們將一個特定的狀態(tài)與一個類相對應(yīng)起來,,也就意味著將一個類事例化,。 盡管相同的類對應(yīng)的實(shí)例其狀態(tài)千差萬別,但其本質(zhì)都對應(yīng)著同一段代碼,。在JAVA中,,一個類通常有著一個.class文件,但也有例外,。在JAVA的運(yùn)行 時(shí)環(huán)境中(Java runtime),,每一個類都有一個以第一類(first-class)的Java對象所表現(xiàn)出現(xiàn)的代碼,其是java.lang.Class的實(shí)例,。我 們編譯一個JAVA文件,,編譯器都會嵌入一個public, static, final修飾的類型為java.lang.Class,,名稱為class的域變量在其字節(jié)碼文件中。因?yàn)槭褂昧藀ublic修飾,,我們可以采用如下的形 式對其訪問:

java.lang.Class klass = Myclass.class; 一旦一個類被載入JVM中,,同一個類就不會被再次載入了(切記,,同一個類)。這里存在一個問題就是什么是“同一個類”,?正如一個對象有一個具體的狀態(tài),,即 標(biāo)識,一個對象始終和其代碼(類)相關(guān)聯(lián),。同理,,載入JVM的類也有一個具體的標(biāo)識,我們接下來看,。

在JAVA中,,一個類用其完全匹配類名(fully qualified class name)作為標(biāo)識,這里指的完全匹配類名包括包名和類名,。但在JVM中一個類用其全名和一個加載類ClassLoader的實(shí)例作為唯一標(biāo)識,。因此,如 果一個名為Pg的包中,,有一個名為Cl的類,,被類加載器KlassLoader的一個實(shí)例kl1加載,Cl的實(shí)例,,即C1.class在JVM中表示為 (Cl, Pg, kl1),。這意味著兩個類加載器的實(shí)例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它們所加載的類也因此完全不同,,互不兼容的,。那么在JVM中到底有多少種類加載器的實(shí)例?下一節(jié)我們揭示答案,。

類加載器



在JVM中,,每一個類都被java.lang.ClassLoader的一些實(shí)例來加載.類ClassLoader是在包中java.lang里,開發(fā)者可以自由地繼承它并添加自己的功能來加載類,。

無論何時(shí)我們鍵入java MyMainClass來開始運(yùn)行一個新的JVM,,“引導(dǎo)類加載器(bootstrap class loader)”負(fù)責(zé)將一些關(guān)鍵的Java類,如java.lang.Object和其他一些運(yùn)行時(shí)代碼先加載進(jìn)內(nèi)存中,。運(yùn)行時(shí)的類在JRE\lib \rt.jar包文件中,。因?yàn)檫@屬于系統(tǒng)底層執(zhí)行動作,我們無法在JAVA文檔中找到引導(dǎo)類加載器的工作細(xì)節(jié),?;谕瑯拥脑颍龑?dǎo)類加載器的行為在各 JVM之間也是大相徑庭,。
同理,,如果我們按照如下方式: log(java.lang.String.class.getClassLoader()); 來獲取java的核心運(yùn)行時(shí)類的加載器,就會得到null,。

接下來介紹java的擴(kuò)展類加載器,。擴(kuò)展庫提供比java運(yùn)行代碼更多的特性,,我們可以把擴(kuò)展庫保存在由java.ext.dirs屬性提供的路徑中。

(編輯注:java.ext.dirs屬性指的是系統(tǒng)屬性下的一個key,,所有的系統(tǒng)屬性可以通過System.getProperties()方法獲 得,。在編者的系統(tǒng)中,java.ext.dirs的value是” C:\Program Files\Java\jdk1.5.0_04\jre\lib\ext”,。下面將要談到的如java.class.path也同屬系統(tǒng)屬性的一個 key,。)

類ExtClassLoader專門用來加載所有java.ext.dirs下的.jar文件。開發(fā)者可以通過把自己的.jar文件或庫文件加入到擴(kuò)展目錄的classpath,,使其可以被擴(kuò)展類加載器讀取。

從開發(fā)者的角度,,第三種同樣也是最重要的一種類加載器是AppClassLoader,。這種類加載器用來讀取所有的對應(yīng)在java.class.path系統(tǒng)屬性的路徑下的類。

Sun的java指南中,,文章“理解擴(kuò)展類加載”(Understanding Extension Class Loading)對以上三個類加載器路徑有更詳盡的解釋,,這是其他幾個JDK中的類加載器
●java.net.URLClassLoader
●java.security.SecureClassLoader
●java.rmi.server.RMIClassLoader
●sun.applet.AppletClassLoader

java.lang.Thread,包含了public ClassLoader getContextClassLoader()方法,,這一方法返回針對一具體線程的上下文環(huán)境類加載器,。此類加載器由線程的創(chuàng)建者提供,以供此線程中運(yùn) 行的代碼在需要加載類或資源時(shí)使用,。如果此加載器未被建立,,缺省是其父線程的上下文類加載器。原始的類加載器一般由讀取應(yīng)用程序的類加載器建立,。

類加載器如何工作,?
除了引導(dǎo)類加載器,所有的類加載器都有一個父類加載器,,不僅如此,,所有的類加載器也都是java.lang.ClassLoader類型。以上兩種類加載 器是不同的,,而且對于開發(fā)者自訂制的類加載器的正常運(yùn)行也至關(guān)重要,。最重要的方面是正確設(shè)置父類加載器。任何類加載器,,其父類加載器是加載該類加載器的類 加載器實(shí)例,。(記住,類加載器本身也是一個類?。?br>
使用loadClass()方法可以從類加載器中獲得該類,。我們可以通過java.lang.ClassLoader的源代碼來了解該方法工作的細(xì)節(jié),如下:

protected synchronized Class<?> loadClass
    (String name, boolean resolve)
    throws ClassNotFoundException{

    // First check if the class is already loaded
    Class c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                c = findBootstrapClass0(name);
            }
        } catch (ClassNotFoundException e) {
            // If still not found, then invoke
            // findClass to find the class.
            c = findClass(name);
        }
    }
    if (resolve) {
            resolveClass(c);
    }
    return c;
}

我們可以使用ClassLoader的兩種構(gòu)造方法來設(shè)置父類加載器:

public class MyClassLoader extends ClassLoader{

    public MyClassLoader(){
        super(MyClassLoader.class.getClassLoader());
    }
}



public class MyClassLoader extends ClassLoader{

    public MyClassLoader(){
        super(getClass().getClassLoader());
    }
}

第一種方式較為常用,,因?yàn)橥ǔ2唤ㄗh在構(gòu)造方法里調(diào)用getClass()方法,,因?yàn)閷ο蟮某跏蓟皇窃跇?gòu)造方法的出口處才完全完成,。因此,如果父類加載 器被正確建立,,當(dāng)要示從一個類加載器的實(shí)例獲得一個類時(shí),,如果它不能找到這個類,它應(yīng)該首先去訪問其父類,。如果父類不能找到它(即其父類也不能找不這個 類,,等等),,而且如果findBootstrapClass0()方法也失敗了,則調(diào)用findClass()方法,。findClass()方法的缺省實(shí) 現(xiàn)會拋出ClassNotFoundException,當(dāng)它們繼承java.lang.ClassLoader來訂制類加載器時(shí)開發(fā)者需要實(shí)現(xiàn)這個方 法,。findClass()的缺省實(shí)現(xiàn)方式如下:

    protected Class<?> findClass(String name)
        throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

在findClass()方法內(nèi)部,,類加載器需要獲取任意來源的字節(jié)碼。來源可以是文件系統(tǒng),,URL,數(shù)據(jù)庫,,可以產(chǎn)生字節(jié)碼的另一個應(yīng)用程序,及其他類 似的可以產(chǎn)生java規(guī)范的字節(jié)碼的來源,。你甚至可以使用BCEL (Byte Code Engineering Library:字節(jié)碼工程庫),它提供了運(yùn)行時(shí)創(chuàng)建類的捷徑,。BCEL已經(jīng)被成功地使用在以下方面:編譯器,,優(yōu)化器,混淆器,,代碼產(chǎn)生器及其他分析工 具。一旦字節(jié)碼被檢索,,此方法就會調(diào)用defineClass()方法,,此行為對不同的類加載實(shí)例是有差異的。因此,,如果兩個類加載實(shí)例從同一個來源定義 一個類,,所定義的結(jié)果是不同的。

JAVA語言規(guī)范(Java language specification)詳細(xì)解釋了JAVA執(zhí)行引擎中的類或接口的加載(loading),,鏈接(linking)或初始化(initialization)過程,。

圖一顯示了一個主類稱為MyMainClass的應(yīng)用程序,。依照之前的闡述,,MyMainClass.class會被AppClassLoader加載。 MyMainClass創(chuàng)建了兩個類加載器的實(shí)例:CustomClassLoader1 和 CustomClassLoader2,他們可以從某數(shù)據(jù)源(比如網(wǎng)絡(luò))獲取名為Target的字節(jié)碼,。這表示類Target的類定義不在應(yīng)用程序類路徑 或擴(kuò)展類路徑,。在這種情況下,如果MyMainClass想要用自定義的類加載器加載Target類,,CustomClassLoader1和 CustomClassLoader2會分別獨(dú)立地加載并定義Target.class類,。這在java中有重要的意義,。如果Target類有一些靜態(tài)的 初始化代碼,并且假設(shè)我們只希望這些代碼在JVM中只執(zhí)行一次,,而這些代碼在我們目前的步驟中會執(zhí)行兩次——分別被不同的 CustomClassLoaders加載并執(zhí)行。如果類Target被兩個CustomClassLoaders加載并創(chuàng)建兩個實(shí)例Target1和 Target2,,如圖一顯示,,它們不是類型兼容的。換句話說,,在JVM中無法執(zhí)行以下代碼:

Target target3 = (Target) target2;

以上代碼會拋出一個ClassCastException,。這是因?yàn)镴VM把他們視為分別不同的類,因?yàn)樗麄儽徊煌念惣虞d器所定義,。這種情況當(dāng)我們不是 使用兩個不同的類加載器CustomClassLoader1 和 CustomClassLoader2,,而是使用同一個類加載器CustomClassLoader的不同實(shí)例時(shí),,也會出現(xiàn)同樣的錯誤,。這些會在本文后邊 用具體代碼說明,。


圖1. 在同一個JVM中多個類加載器加載同一個目標(biāo)類

關(guān)于類加載,、定義和鏈接的更多解釋,,請參考Andreas Schaefer的"Inside Class Loaders."

為什么我們需要我們自己的類加載器
原因之一為開發(fā)者寫自己的類加載器來控制JVM中的類加載行為,,java中的類靠其包名和類名來標(biāo)識,,對于實(shí)現(xiàn)了 java.io.Serializable接口的類,,serialVersionUID扮演了一個標(biāo)識類版本的重要角色,。這個唯一標(biāo)識是一個類名,、接口 名,、成員方法及屬性等組成的一個64位的哈希字段,,而且也沒有其他快捷的方式來標(biāo)識一個類的版本,。嚴(yán)格說來,,如果以上的都匹配,,那么則屬于同一個類。

但是讓我們思考如下情況:我們需要開發(fā)一個通用的執(zhí)行引擎,??梢詧?zhí)行實(shí)現(xiàn)某一特定接口的任何任務(wù),。當(dāng)任務(wù)被提交到這個引擎,,首先需要加載這個任務(wù)的代碼,。 假設(shè)不同的客戶對此引擎提交了不同的任務(wù),,湊巧,,這些所有的任務(wù)都有一個相同的類名和包名。現(xiàn)在面臨的問題就是這個引擎是否可以針對不同的用戶所提交的信 息而做出不同的反應(yīng),。這一情況在下文的參考一節(jié)有可供下載的代碼樣例,,samepath 和 differentversions,,這兩個目錄分別演示了這一概念,。

圖2 顯示了文件目錄結(jié)構(gòu),,有三個子目錄samepath, differentversions, 和 differentversionspush,,里邊是例子:


圖2. 文件夾結(jié)構(gòu)組織示例

在samepath 中,,類version.Version保存在v1和v2兩個子目錄里,,兩個類具有同樣的類名和包名,,唯一不同的是下邊這行:

    public void fx(){
        log("this = " + this + "; Version.fx(1).");
    }

V1中,,日志記錄中有Version.fx(1),,而在v2中則是Version.fx(2)。把這個兩個存在細(xì)微不同的類放在一個classpath下,,然后運(yùn)行Test類:

set CLASSPATH=.;%CURRENT_ROOT%\v1;%CURRENT_ROOT%\v2
%JAVA_HOME%\bin\java Test


圖3顯示了控制臺輸出,。我們可以看到對應(yīng)著Version.fx(1)的代碼被執(zhí)行了,,因?yàn)轭惣虞d器在classpath首先看到此版本的代碼,。


圖3. 在類路徑中samepath測試排在最前面的version 1

再次運(yùn)行,類路徑做如下微小改動,。

set CLASSPATH=.;%CURRENT_ROOT%\v2;%CURRENT_ROOT%\v1
%JAVA_HOME%\bin\java Test


控制臺的輸出變?yōu)閳D4。對應(yīng)著Version.fx(2)的代碼被加載,,因?yàn)轭惣虞d器在classpath中首先找到它的路徑。


圖4. 在類路徑中samepath測試排在最前面的version 2

根據(jù)以上例子可以很明顯地看出,,類加載器加載在類路徑中被首先找到的元素,。如果我們在v1和v2中刪除了version.Version,,做一個非 version.Version形式的.jar文件,,如myextension.jar,,把它放到對應(yīng)java.ext.dirs的路徑下,,再次執(zhí)行后看 到version.Version不再被AppClassLoader加載,,而是被擴(kuò)展類加載器加載,。如圖5所示,。


圖5. AppClassLoader及ExtClassLoader

繼續(xù)這個例子,文件夾differentversions包含了一個RMI執(zhí)行引擎,,客戶端可以提供給執(zhí)行引擎任何實(shí)現(xiàn)了common.TaskIntf 接口的任務(wù),。子文件夾client1 和 client2包含了類client.TaskImpl有個細(xì)微不同的兩個版本,。兩個類的區(qū)別在以下幾行:

    static{
        log("client.TaskImpl.class.getClassLoader
        (v1) : " + TaskImpl.class.getClassLoader());
    }

    public void execute(){
        log("this = " + this + "; execute(1)");
    }

在client1和client2里分別有g(shù)etClassLoader(v1) 與 execute(1)和getClassLoader(v2) 與 execute(2)的的log語句。并且,在開始執(zhí)行引擎RMI服務(wù)器的代碼中,,我們隨意地將client2的任務(wù)實(shí)現(xiàn)放在類路徑的前面,。

CLASSPATH=%CURRENT_ROOT%\common;%CURRENT_ROOT%\server;
    %CURRENT_ROOT%\client2;%CURRENT_ROOT%\client1
%JAVA_HOME%\bin\java server.Server


如圖6,,7,,8的屏幕截圖,,在客戶端VM,,各自的client.TaskImpl類被加載、實(shí)例化,,并發(fā)送到服務(wù)端的VM來執(zhí)行。從服務(wù)端的控制臺,,可以 明顯看到client.TaskImpl代碼只被服務(wù)端的VM執(zhí)行一次,,這個單一的代碼版本在服務(wù)端多次生成了許多實(shí)例,,并執(zhí)行任務(wù),。



圖6. 執(zhí)行引擎服務(wù)器控制臺

圖6顯示了服務(wù)端的控制臺,,加載并執(zhí)行兩個不同的客戶端的請求,,如圖7,,8所示,。需要注意的是,代碼只被加載了一次(從靜態(tài)初始化塊的日志中也可以明顯看出),,但對于客戶端的調(diào)用這個方法被執(zhí)行了兩次。


圖7. 執(zhí)行引擎客戶端 1控制臺 

圖7中,,客戶端VM加載了含有client.TaskImpl.class.getClassLoader(v1)的日志內(nèi)容的類TaskImpl的代碼,,并提供給服務(wù)端的執(zhí)行引擎。圖8的客戶端VM加載了另一個TaskImpl的代碼,,并發(fā)送給服務(wù)端,。


圖8. 執(zhí)行引擎客戶端 2控制臺 

在客戶端的VM中,類client.TaskImpl被分別加載,,初始化,,并發(fā)送到服務(wù)端執(zhí)行。圖6還揭示了client.TaskImpl的代碼只在服 務(wù)端的VM中加載了一次,,但這“唯一的一次”卻在服務(wù)端創(chuàng)造了許多實(shí)例并執(zhí)行,?;蛟S客戶端1該不高興了因?yàn)椴⒉皇撬? client.TaskImpl(v1)的方法調(diào)用被服務(wù)端執(zhí)行了,,而是其他的一些代碼,。如何解決這一問題,?答案就是實(shí)現(xiàn)定制的類加載器,。

定制類加載器

要較好地控制類的加載,就要實(shí)現(xiàn)定制的類加載器,。所有自定義的類加載器都應(yīng)繼承自java.lang.ClassLoader,。而且在構(gòu)造方法中,我們也 應(yīng)該設(shè)置父類加載器,。然后重寫findClass()方法,。differentversionspush文件夾包含了一個叫做 FileSystemClassLoader的自訂制的類加載器,。其結(jié)構(gòu)如圖9所示。


圖9. 定制類加載器關(guān)系

以下是在common.FileSystemClassLoader實(shí)現(xiàn)的主方法:

     public byte[] findClassBytes(String className){

        try{
            String pathName = currentRoot +
                File.separatorChar + className.
                replace('.', File.separatorChar)
                + ".class";
            FileInputStream inFile = new
                FileInputStream(pathName);
            byte[] classBytes = new
                byte[inFile.available()];
            inFile.read(classBytes);
            return classBytes;
        }
        catch (java.io.IOException ioEx){
            return null;
        }
    }

    public Class findClass(String name)throws
        ClassNotFoundException{

        byte[] classBytes = findClassBytes(name);
        if (classBytes==null){
            throw new ClassNotFoundException();
        }
        else{
            return defineClass(name, classBytes,
                0, classBytes.length);
        }
    }

    public Class findClass(String name, byte[]
        classBytes)throws ClassNotFoundException{

        if (classBytes==null){
            throw new ClassNotFoundException(
                "(classBytes==null)");
        }
        else{
            return defineClass(name, classBytes,
                0, classBytes.length);
        }
    }

    public void execute(String codeName,
        byte[] code){

        Class klass = null;
        try{
            klass = findClass(codeName, code);
            TaskIntf task = (TaskIntf)
                klass.newInstance();
            task.execute();
        }
        catch(Exception exception){
            exception.printStackTrace();
        }
    }

這個類供客戶端把client.TaskImpl(v1)轉(zhuǎn)換成字節(jié)數(shù)組,,之后此字節(jié)數(shù)組被發(fā)送到RMI服務(wù)端,。在服務(wù)端,一個同樣的類用來把字節(jié)數(shù)組的內(nèi)容轉(zhuǎn)換回代碼,??蛻舳舜a如下:

public class Client{

    public static void main (String[] args){

        try{
            byte[] code = getClassDefinition
                ("client.TaskImpl");
            serverIntf.execute("client.TaskImpl",
                code);
            }
            catch(RemoteException remoteException){
                remoteException.printStackTrace();
            }
        }

    private static byte[] getClassDefinition
        (String codeName){
        String userDir = System.getProperties().
            getProperty("BytePath");
        FileSystemClassLoader fscl1 = null;

        try{
            fscl1 = new FileSystemClassLoader
                (userDir);
        }
        catch(FileNotFoundException
            fileNotFoundException){
            fileNotFoundException.printStackTrace();
        }
        return fscl1.findClassBytes(codeName);
    }
}

在執(zhí)行引擎中,,從客戶端收到的代碼被送到定制的類加載器中,。定制的類加載器把其從字節(jié)數(shù)組定義成類,實(shí)例化并執(zhí)行,。需要指出的是,,對每一個客戶請求,我們 用類FileSystemClassLoader的不同實(shí)例來定義客戶端提交的client.TaskImpl,。而且,,client.TaskImpl并 不在服務(wù)端的類路徑中。這也就意味著當(dāng)我們在FileSystemClassLoader調(diào)用findClass()方法時(shí),,findClass()調(diào)用 內(nèi)在的defineClass()方法,。類client.TaskImpl被特定的類加載器實(shí)例所定義。因此,,當(dāng) FileSystemClassLoader的一個新的實(shí)例被使用,類又被重新定義為字節(jié)數(shù)組,。因此,對每個客戶端請求類client.TaskImpl 被多次定義,,我們就可以在相同執(zhí)行引擎JVM中執(zhí)行不同的client.TaskImpl的代碼,。

     public void execute(String codeName, byte[] code)throws RemoteException{

        FileSystemClassLoader fileSystemClassLoader = null;

        try{
            fileSystemClassLoader = new FileSystemClassLoader();
            fileSystemClassLoader.execute(codeName, code);
        }
        catch(Exception exception){
            throw new RemoteException(exception.getMessage());
        }
    }



示例在differentversionspush文件夾下,。服務(wù)端和客戶端的控制臺界面分別如圖10,,11,,12所示:

 


                                                            圖10. 定制類加載器執(zhí)行引擎

圖10顯示的是定制的類加載器控制臺,。我們可以看到client.TaskImpl的代碼被多次加載,。實(shí)際上針對每一個客戶端,類都被加載并初始化,。


    圖11. 定制類加載器,,客戶端1

    圖11中,,含有client.TaskImpl.class.getClassLoader(v1)的日志記錄的類TaskImpl的代碼被客戶端的VM 加載,,然后送到服務(wù)端。圖12 另一個客戶端把包含有client.TaskImpl.class.getClassLoader(v1)的類代碼加載并送往服務(wù)端,。


圖12. 定制類加載器,,客戶端1

這段代碼演示了我們?nèi)绾卫貌煌念惣虞d器實(shí)例來在同一個VM上執(zhí)行不同版本的代碼。

J2EE的類加載器


J2EE的服務(wù)器傾向于以一定間隔頻率,,丟棄原有的類并重新載入新的類,。在某些情況下會這樣執(zhí)行,而有些情況則不,。同樣,,對于一個web服務(wù)器如果要丟棄 一個servlet實(shí)例,可能是服務(wù)器管理員的手動操作,,也可能是此實(shí)例長時(shí)間未相應(yīng),。當(dāng)一個JSP頁面被首次請求,容器會把此JSP頁面翻譯成一個具有 特定形式的servlet代碼,。一旦servlet代碼被創(chuàng)建,,容器就會把這個servlet翻譯成class文件等待被使用。對于提交給容器的每次請 求,,容器都會首先檢查這個JSP文件是否剛被修改過,。是的話就重新翻譯此文件,這可以確保每次的請求都是及時(shí)更新的,。企業(yè)級的部署方案以.ear, .war, .rar等形式的文件,,同樣需要重復(fù)加載,可能是隨意的也可能是依照某種配置方案定期執(zhí)行,。對所有的這些情況——類的加載,、卸載、重新加載……全部都是建 立在我們控制應(yīng)用服務(wù)器的類加載機(jī)制的基礎(chǔ)上的,。實(shí)現(xiàn)這些需要擴(kuò)展的類加載器,,它可以執(zhí)行由其自身所定義的類。Brett Peterson已經(jīng)在他的文章 Understanding J2EE Application Server Class Loading Architectures給出了J2EE應(yīng)用服務(wù)器的類加載方案的詳細(xì)說明,,詳見網(wǎng)站TheServerSide.com,。

結(jié)要

本文探討了類載入到虛擬機(jī)是如何進(jìn)行唯一標(biāo)識的,,以及類如果存在同樣的類名和包名時(shí)所產(chǎn)生的問題,。因?yàn)闆]有一個直接可用的類版

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多