日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Java類加載內(nèi)幕

瀏覽:331日期:2024-06-13 10:11:09
內(nèi)容: Java類加載內(nèi)幕作者:Binildas Christudas 01/26/2005翻譯:purplerain版權(quán)聲明:可以任意轉(zhuǎn)載,轉(zhuǎn)載時(shí)請務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明作者:Binildas;purplerain原文地址:http://www.onjava.com/pub/a/onjava/2005/01/26/classloading.html中文地址:http://www.matrix.org.cn/resource/article/43/43875_Class_Loading.html關(guān)鍵詞: Java Class Loading類加載是java語言提供的最強(qiáng)大的機(jī)制之一。盡管類加載并不是討論的熱點(diǎn)話題,但所有的編程人員都應(yīng)該了解其工作機(jī)制,明白如何做才能讓其滿足我們的需要。這能有效節(jié)省我們的編碼時(shí)間,從不斷調(diào)試ClassNotFoundException, ClassCastException的工作中解脫出來。這篇文章從基礎(chǔ)講起,比如代碼與數(shù)據(jù)的不同之處是什么,他們是如何構(gòu)成一個(gè)實(shí)例或?qū)ο蟮摹H缓笊钊胩接慾ava虛擬機(jī)(JVM)是如何利用類加載器讀取代碼,以及java中類加載器的主要類型。接著用一個(gè)類加載的基本算法看一下類加載器如何加載一個(gè)內(nèi)部類。本文的下一節(jié)演示一段代碼來說明擴(kuò)展和開發(fā)屬于自己的類加載器的必要性。緊接著解釋如何使用定制的類加載器來完成一個(gè)一般意義上的任務(wù),使其可以加載任意遠(yuǎn)端客戶的代碼,在JVM中定義,實(shí)例化并執(zhí)行它。本文包括了J2EE關(guān)于類加載的規(guī)范——事實(shí)上這已經(jīng)成為了J2EE的標(biāo)準(zhǔn)之一。類與數(shù)據(jù)一個(gè)類代表要執(zhí)行的代碼,而數(shù)據(jù)則表示其相關(guān)狀態(tài)。狀態(tài)時(shí)常改變,而代碼則不會。當(dāng)我們將一個(gè)特定的狀態(tài)與一個(gè)類相對應(yīng)起來,也就意味著將一個(gè)類事例化。盡管相同的類對應(yīng)的實(shí)例其狀態(tài)千差萬別,但其本質(zhì)都對應(yīng)著同一段代碼。在JAVA中,一個(gè)類通常有著一個(gè).class文件,但也有例外。在JAVA的運(yùn)行時(shí)環(huán)境中(Java runtime),每一個(gè)類都有一個(gè)以第一類(first-class)的Java對象所表現(xiàn)出現(xiàn)的代碼,其是java.lang.Class的實(shí)例。我們編譯一個(gè)JAVA文件,編譯器都會嵌入一個(gè)public, static, final修飾的類型為java.lang.Class,名稱為class的域變量在其字節(jié)碼文件中。因?yàn)槭褂昧藀ublic修飾,我們可以采用如下的形式對其訪問:java.lang.Class klass = Myclass.class;一旦一個(gè)類被載入JVM中,同一個(gè)類就不會被再次載入了(切記,同一個(gè)類)。這里存在一個(gè)問題就是什么是“同一個(gè)類?正如一個(gè)對象有一個(gè)具體的狀態(tài),即標(biāo)識,一個(gè)對象始終和其代碼(類)相關(guān)聯(lián)。同理,載入JVM的類也有一個(gè)具體的標(biāo)識,我們接下來看。在JAVA中,一個(gè)類用其完全匹配類名(fully qualified class name)作為標(biāo)識,這里指的完全匹配類名包括包名和類名。但在JVM中一個(gè)類用其全名和一個(gè)加載類ClassLoader的實(shí)例作為唯一標(biāo)識。因此,如果一個(gè)名為Pg的包中,有一個(gè)名為Cl的類,被類加載器KlassLoader的一個(gè)實(shí)例kl1加載,Cl的實(shí)例,即C1.class在JVM中表示為(Cl, Pg, kl1)。這意味著兩個(gè)類加載器的實(shí)例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它們所加載的類也因此完全不同,互不兼容的。那么在JVM中到底有多少種類加載器的實(shí)例?下一節(jié)我們揭示答案。類加載器在JVM中,每一個(gè)類都被java.lang.ClassLoader的一些實(shí)例來加載.類ClassLoader是在包中java.lang里,開發(fā)者可以自由地繼承它并添加自己的功能來加載類。無論何時(shí)我們鍵入java MyMainClass來開始運(yùn)行一個(gè)新的JVM,“引導(dǎo)類加載器(bootstrap class loader)負(fù)責(zé)將一些關(guān)鍵的Java類,如java.lang.Object和其他一些運(yùn)行時(shí)代碼先加載進(jìn)內(nèi)存中。運(yùn)行時(shí)的類在JRElibrt.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)屬性下的一個(gè)key,所有的系統(tǒng)屬性可以通過System.getProperties()方法獲得。在編者的系統(tǒng)中,java.ext.dirs的value是 C:Program FilesJavajdk1.5.0_04jrelibext。下面將要談到的如java.class.path也同屬系統(tǒng)屬性的一個(gè)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)對以上三個(gè)類加載器路徑有更詳盡的解釋,這是其他幾個(gè)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)類加載器,所有的類加載器都有一個(gè)父類加載器,不僅如此,所有的類加載器也都是java.lang.ClassLoader類型。以上兩種類加載器是不同的,而且對于開發(fā)者自訂制的類加載器的正常運(yùn)行也至關(guān)重要。最重要的方面是正確設(shè)置父類加載器。任何類加載器,其父類加載器是加載該類加載器的類加載器實(shí)例。(記住,類加載器本身也是一個(gè)類!)使用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)要示從一個(gè)類加載器的實(shí)例獲得一個(gè)類時(shí),如果它不能找到這個(gè)類,它應(yīng)該首先去訪問其父類。如果父類不能找到它(即其父類也不能找不這個(gè)類,等等),而且如果findBootstrapClass0()方法也失敗了,則調(diào)用findClass()方法。findClass()方法的缺省實(shí)現(xiàn)會拋出ClassNotFoundException,當(dāng)它們繼承java.lang.ClassLoader來訂制類加載器時(shí)開發(fā)者需要實(shí)現(xiàn)這個(gè)方法。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é)碼的另一個(gè)應(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í)例是有差異的。因此,如果兩個(gè)類加載實(shí)例從同一個(gè)來源定義一個(gè)類,所定義的結(jié)果是不同的。JAVA語言規(guī)范(Java language specification)詳細(xì)解釋了JAVA執(zhí)行引擎中的類或接口的加載(loading),鏈接(linking)或初始化(initialization)過程。圖一顯示了一個(gè)主類稱為MyMainClass的應(yīng)用程序。依照之前的闡述,MyMainClass.class會被AppClassLoader加載。 MyMainClass創(chuàng)建了兩個(gè)類加載器的實(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被兩個(gè)CustomClassLoaders加載并創(chuàng)建兩個(gè)實(shí)例Target1和Target2,如圖一顯示,它們不是類型兼容的。換句話說,在JVM中無法執(zhí)行以下代碼:Target target3 = (Target) target2;以上代碼會拋出一個(gè)ClassCastException。這是因?yàn)镴VM把他們視為分別不同的類,因?yàn)樗麄儽徊煌念惣虞d器所定義。這種情況當(dāng)我們不是使用兩個(gè)不同的類加載器CustomClassLoader1 和 CustomClassLoader2,而是使用同一個(gè)類加載器CustomClassLoader的不同實(shí)例時(shí),也會出現(xiàn)同樣的錯(cuò)誤。這些會在本文后邊用具體代碼說明。 圖1. 在同一個(gè)JVM中多個(gè)類加載器加載同一個(gè)目標(biāo)類關(guān)于類加載、定義和鏈接的更多解釋,請參考Andreas Schaefer的'Inside Class Loaders.'為什么我們需要我們自己的類加載器原因之一為開發(fā)者寫自己的類加載器來控制JVM中的類加載行為,java中的類靠其包名和類名來標(biāo)識,對于實(shí)現(xiàn)了java.io.Serializable接口的類,serialVersionUID扮演了一個(gè)標(biāo)識類版本的重要角色。這個(gè)唯一標(biāo)識是一個(gè)類名、接口名、成員方法及屬性等組成的一個(gè)64位的哈希字段,而且也沒有其他快捷的方式來標(biāo)識一個(gè)類的版本。嚴(yán)格說來,如果以上的都匹配,那么則屬于同一個(gè)類。但是讓我們思考如下情況:我們需要開發(fā)一個(gè)通用的執(zhí)行引擎。可以執(zhí)行實(shí)現(xiàn)某一特定接口的任何任務(wù)。當(dāng)任務(wù)被提交到這個(gè)引擎,首先需要加載這個(gè)任務(wù)的代碼。假設(shè)不同的客戶對此引擎提交了不同的任務(wù),湊巧,這些所有的任務(wù)都有一個(gè)相同的類名和包名。現(xiàn)在面臨的問題就是這個(gè)引擎是否可以針對不同的用戶所提交的信息而做出不同的反應(yīng)。這一情況在下文的參考一節(jié)有可供下載的代碼樣例,samepath 和 differentversions,這兩個(gè)目錄分別演示了這一概念。圖2 顯示了文件目錄結(jié)構(gòu),有三個(gè)子目錄samepath, differentversions, 和 differentversionspush,里邊是例子: 圖2. 文件夾結(jié)構(gòu)組織示例在samepath 中,類version.Version保存在v1和v2兩個(gè)子目錄里,兩個(gè)類具有同樣的類名和包名,唯一不同的是下邊這行: public void fx(){ log('this = ' + this + '; Version.fx(1).'); }V1中,日志記錄中有Version.fx(1),而在v2中則是Version.fx(2)。把這個(gè)兩個(gè)存在細(xì)微不同的類放在一個(gè)classpath下,然后運(yùn)行Test類:set CLASSPATH=.;%CURRENT_ROOT%v1;%CURRENT_ROOT%v2%JAVA_HOME%binjava 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%binjava Test控制臺的輸出變?yōu)閳D4。對應(yīng)著Version.fx(2)的代碼被加載,因?yàn)轭惣虞d器在classpath中首先找到它的路徑。圖4. 在類路徑中samepath測試排在最前面的version 2根據(jù)以上例子可以很明顯地看出,類加載器加載在類路徑中被首先找到的元素。如果我們在v1和v2中刪除了version.Version,做一個(gè)非version.Version形式的.jar文件,如myextension.jar,把它放到對應(yīng)java.ext.dirs的路徑下,再次執(zhí)行后看到version.Version不再被AppClassLoader加載,而是被擴(kuò)展類加載器加載。如圖5所示。 圖5. AppClassLoader及ExtClassLoader繼續(xù)這個(gè)例子,文件夾differentversions包含了一個(gè)RMI執(zhí)行引擎,客戶端可以提供給執(zhí)行引擎任何實(shí)現(xiàn)了common.TaskIntf接口的任務(wù)。子文件夾client1 和 client2包含了類client.TaskImpl有個(gè)細(xì)微不同的兩個(gè)版本。兩個(gè)類的區(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%binjava server.Server如圖6,7,8的屏幕截圖,在客戶端VM,各自的client.TaskImpl類被加載、實(shí)例化,并發(fā)送到服務(wù)端的VM來執(zhí)行。從服務(wù)端的控制臺,可以明顯看到client.TaskImpl代碼只被服務(wù)端的VM執(zhí)行一次,這個(gè)單一的代碼版本在服務(wù)端多次生成了許多實(shí)例,并執(zhí)行任務(wù)。 圖6. 執(zhí)行引擎服務(wù)器控制臺圖6顯示了服務(wù)端的控制臺,加載并執(zhí)行兩個(gè)不同的客戶端的請求,如圖7,8所示。需要注意的是,代碼只被加載了一次(從靜態(tài)初始化塊的日志中也可以明顯看出),但對于客戶端的調(diào)用這個(gè)方法被執(zhí)行了兩次。 圖7. 執(zhí)行引擎客戶端 1控制臺 圖7中,客戶端VM加載了含有client.TaskImpl.class.getClassLoader(v1)的日志內(nèi)容的類TaskImpl的代碼,并提供給服務(wù)端的執(zhí)行引擎。圖8的客戶端VM加載了另一個(gè)TaskImpl的代碼,并發(fā)送給服務(wù)端。 圖8. 執(zhí)行引擎客戶端 2控制臺 在客戶端的VM中,類client.TaskImpl被分別加載,初始化,并發(fā)送到服務(wù)端執(zhí)行。圖6還揭示了client.TaskImpl的代碼只在服務(wù)端的VM中加載了一次,但這“唯一的一次卻在服務(wù)端創(chuàng)造了許多實(shí)例并執(zhí)行。或許客戶端1該不高興了因?yàn)椴⒉皇撬腸lient.TaskImpl(v1)的方法調(diào)用被服務(wù)端執(zhí)行了,而是其他的一些代碼。如何解決這一問題?答案就是實(shí)現(xiàn)定制的類加載器。定制類加載器要較好地控制類的加載,就要實(shí)現(xiàn)定制的類加載器。所有自定義的類加載器都應(yīng)繼承自java.lang.ClassLoader。而且在構(gòu)造方法中,我們也應(yīng)該設(shè)置父類加載器。然后重寫findClass()方法。differentversionspush文件夾包含了一個(gè)叫做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(); } }這個(gè)類供客戶端把client.TaskImpl(v1)轉(zhuǎn)換成字節(jié)數(shù)組,之后此字節(jié)數(shù)組被發(fā)送到RMI服務(wù)端。在服務(wù)端,一個(gè)同樣的類用來把字節(jié)數(shù)組的內(nèi)容轉(zhuǎn)換回代碼。客戶端代碼如下: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í)行。需要指出的是,對每一個(gè)客戶請求,我們用類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的一個(gè)新的實(shí)例被使用,類又被重新定義為字節(jié)數(shù)組。因此,對每個(gè)客戶端請求類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í)際上針對每一個(gè)客戶端,類都被加載并初始化。 圖11. 定制類加載器,客戶端1圖11中,含有client.TaskImpl.class.getClassLoader(v1)的日志記錄的類TaskImpl的代碼被客戶端的VM加載,然后送到服務(wù)端。圖12 另一個(gè)客戶端把包含有client.TaskImpl.class.getClassLoader(v1)的類代碼加載并送往服務(wù)端。 圖12. 定制類加載器,客戶端1這段代碼演示了我們?nèi)绾卫貌煌念惣虞d器實(shí)例來在同一個(gè)VM上執(zhí)行不同版本的代碼。J2EE的類加載器J2EE的服務(wù)器傾向于以一定間隔頻率,丟棄原有的類并重新載入新的類。在某些情況下會這樣執(zhí)行,而有些情況則不。同樣,對于一個(gè)web服務(wù)器如果要丟棄一個(gè)servlet實(shí)例,可能是服務(wù)器管理員的手動操作,也可能是此實(shí)例長時(shí)間未相應(yīng)。當(dāng)一個(gè)JSP頁面被首次請求,容器會把此JSP頁面翻譯成一個(gè)具有特定形式的servlet代碼。一旦servlet代碼被創(chuàng)建,容器就會把這個(gè)servlet翻譯成class文件等待被使用。對于提交給容器的每次請求,容器都會首先檢查這個(gè)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)闆]有一個(gè)直接可用的類版本管理機(jī)制,所以如果我們要按自己的意愿來加載類時(shí),需要自己訂制類加載器來擴(kuò)展其行為。我們可以利用許多J2EE服務(wù)器所提供的“熱部署功能來重新加載一個(gè)新版本的類,而不改動服務(wù)器的VM。即使不涉及應(yīng)用服務(wù)器,我們也可以利用定制類加載器來控制java應(yīng)用程序載入類時(shí)的具體行為。Ted Neward的書Server-Based Java Programming中詳細(xì)闡述java的類加載,J2EE的API以及使用他們的最佳途徑。參考●本文的源碼:Download File Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd Java類加載內(nèi)幕作者:Binildas Christudas 01/26/2005翻譯:purplerain版權(quán)聲明:可以任意轉(zhuǎn)載,轉(zhuǎn)載時(shí)請務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明作者:Binildas;p
標(biāo)簽: Java
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品久久久久av蜜臀| 亚洲永久字幕| 99精品在线| 伊人网在线播放| 蜜臀va亚洲va欧美va天堂| 成人黄色av| 日本亚州欧洲精品不卡| 中文字幕人成乱码在线观看 | 日韩欧美中文字幕电影| 麻豆国产在线| 日韩和欧美的一区| 久久久久.com| 久久不卡日韩美女| 久久亚洲电影| 亚洲黄色网址| 国产精品一区二区精品| 男人天堂欧美日韩| 日韩不卡免费高清视频| 青青草伊人久久| 图片区亚洲欧美小说区| 高清一区二区三区av| 91成人精品观看| 国产视频亚洲| 欧美日韩在线观看视频小说| 久久精品五月| 国产日韩中文在线中文字幕| 视频在线在亚洲| 国产一在线精品一区在线观看| 免费日韩一区二区三区| 日韩va欧美va亚洲va久久| 亚洲一区国产| 欧美日韩第一| 日韩精品欧美| 色网在线免费观看| 国产一区二区三区日韩精品| 久久国产视频网| 日韩毛片网站| 亚洲欧美网站| 亚洲黄色影院| 亚洲国产专区| 91精品蜜臀一区二区三区在线| 国产aa精品| 国产成人精品一区二区三区视频| 欧美一区自拍| 日韩国产在线不卡视频| 深夜日韩欧美| 亚洲专区视频| 亚洲永久精品唐人导航网址| 免费日韩视频| 免费观看久久久4p| 一区二区亚洲视频| 蜜臀久久久久久久| 视频一区在线播放| 美日韩精品视频| 丝瓜av网站精品一区二区| 国产精品女主播一区二区三区| 狠狠久久婷婷| 视频在线观看一区| 亚洲欧美激情诱惑| 9色精品在线| 亚洲综合日韩| 蜜桃视频一区二区三区在线观看| 中文字幕av一区二区三区人| 亚洲一区二区三区久久久| 三级在线观看一区二区| 免费视频一区二区| 色狠狠一区二区三区| 91成人精品在线| 国产精品久久乐| 国产精品日韩精品在线播放 | 精品久久97| 麻豆91精品视频| 精品一区二区三区中文字幕 | 午夜在线一区| 久久亚洲欧美| 日韩精品免费一区二区夜夜嗨| 日韩一区二区三区在线看| 青草久久视频| 麻豆91在线播放| 热三久草你在线| 亚洲午夜电影| 久久国产精品99国产| 三级一区在线视频先锋| 日韩一区二区三区免费视频| 欧美亚洲专区| 久久丁香四色| 成人va天堂| 日韩中文字幕91| 日韩高清不卡一区| 麻豆国产精品一区二区三区| 国产h片在线观看| 伊人久久婷婷| 日本欧美一区二区| 精品一区91| 精品欧美激情在线观看| 免费观看在线综合| 国产精品天天看天天狠| av中文字幕在线观看第一页| 欧美日韩亚洲在线观看| 美美哒免费高清在线观看视频一区二区 | 日韩免费视频| 99亚洲精品| 欧美日韩黄网站| 中文在线а√在线8| 亚洲一区二区三区高清| 国产午夜一区| 日韩精品电影| 亚洲一区av| 久久精品国产免费| 亚洲精品a级片| 国产日韩欧美一区二区三区| 欧美aa在线观看| 99riav国产精品| 国产精品一级在线观看| 色爱av综合网| 日韩精品一区二区三区中文| 国产美女高潮在线观看| 在线一区二区三区视频| 国际精品欧美精品| 婷婷久久一区| 欧美极品中文字幕| 国产一在线精品一区在线观看| 91精品国产一区二区在线观看| 天堂中文av在线资源库| 亚洲一二av| 免费一二一二在线视频| 日韩区欧美区| 日韩av福利| 日本欧美一区| 亚洲国产专区| 国产精品免费99久久久| 午夜久久福利| 麻豆一区二区三| 亚洲欧美日韩国产综合精品二区| 久久精品系列| 亚洲精品高潮| 亚洲午夜黄色| 久久亚洲精品中文字幕| 天堂成人免费av电影一区| 精品欧美日韩精品| 亚洲欧美久久精品| 尤物tv在线精品| 免费看一区二区三区| 石原莉奈在线亚洲二区| 97se综合| 国产精品一区二区av日韩在线| 香蕉人人精品| 久草精品视频| 日韩一区二区三区精品| 欧美粗暴jizz性欧美20| 精品视频高潮| 日韩精品亚洲专区| 在线午夜精品| 韩国精品主播一区二区在线观看| 国产欧美综合一区二区三区| 中文久久精品| 人人精品亚洲| 久久久久伊人| 日韩1区2区日韩1区2区| 麻豆精品网站| 欧美~级网站不卡| 国产aⅴ精品一区二区四区| 日本视频中文字幕一区二区三区| 午夜久久黄色| 99久久婷婷| 理论片午夜视频在线观看| 国产精品白丝久久av网站| 亚洲精品亚洲人成在线观看| 日韩一区二区久久| 日韩精品午夜| 日本不良网站在线观看| 美女视频黄久久| 91精品视频一区二区| 麻豆成人在线| 国产一区二区三区自拍| 伊人久久视频| 精品视频自拍| 国产极品模特精品一二| 日韩不卡一区二区三区| 中文字幕一区二区三区日韩精品| 亚洲精品va| 在线日韩一区| 中文字幕系列一区| 在线人成日本视频| 福利在线一区| 精品资源在线| 免费在线观看一区| 国产欧美日韩在线一区二区| 亚洲精品乱码| 蜜桃视频一区二区三区在线观看| 91高清一区| 免费av一区二区三区四区| 欧美sss在线视频| 四虎884aa成人精品最新| 欧美日韩免费看片| 欧美日韩国产观看视频| 色一区二区三区四区| 三上亚洲一区二区| 欧美国产偷国产精品三区| 国产成人免费视频网站视频社区|