<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    精彩的人生

    好好工作,好好生活

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      147 Posts :: 0 Stories :: 250 Comments :: 0 Trackbacks

    #

    先看個例子:
    <xsl:call-template name="footer">
    <xsl:with-param name="date" select="@lastupdate"/>
    </xsl:call-template>
    <xsl:template name="footer">
    <xsl:param name="date">today</xsl:param>
    <hr/>
    <xsl:text>Last update: </xsl:text>
    <xsl:value-of select="$date"/>
    </xsl:template>
    對xml模板 來說,name屬性是很關(guān)鍵的 call-template /apply-template 的name必須要和模板的name
    相對應(yīng)。模板相當于一個函數(shù),可以暫時這么看。而name相當于函數(shù)名稱把。
    在call-template中 使用xsl:with-param 相當于函數(shù)參數(shù)輸入
    而參數(shù)聲明相當就是在xsl:template的 xsl:param
    說到xsl:variable。
    可以用<xsl:variable name="ShowDepth"><計算的值></xsl:variable>來聲明
    相當于c中的  const 因為變量一旦聲明就無法再被改變。
    對于xsl:param和xsl:variable 都可以用 $+name 來直接選擇比如
    <xsl:value-of select="$date"/>  就是選擇date變量或者參數(shù)
    變量和參數(shù),都是有聲明范圍的 這點和語言中的道理一樣。
    最后最最重要一點 :xsl的variable是常量不能再改變
    				
    						
    								
    										不要被它的名稱迷惑、
    								
    						
    				
    		
    posted @ 2007-03-14 16:28 hopeshared 閱讀(5391) | 評論 (1)編輯 收藏

         摘要: 作者:李紅霞時間:2006-10-19聲明:本文可以算作Axis2用戶手冊的翻譯,但是翻譯后的文本是經(jīng)過作者理解寫出來的,可能有些偏差,歡迎討論。本文屬作者原創(chuàng),允許轉(zhuǎn)載,但請注明出處。 英文原文http://ws.apache.org/axis2/1_0/userguide.html ? ...  閱讀全文
    posted @ 2006-10-23 16:46 hopeshared 閱讀(7847) | 評論 (9)編輯 收藏

    java中的類是動態(tài)加載的,我們先看一下我們常用的類加載方式,先有一個感性的認識,才能進一步
    深入討論,類加載無非就是下面三種方式。
    class A{}
    class B{}
    class C{}
    public class Loader{
    ??? public static void main(String[] args) throws Exception{
    ?????? Class aa=A.class;
    ?????? Class bb=Class.forName("B");
    ?????? Class cc=ClassLoader.getSystemClassLoader().loadClass("C");
    ??? }
    }
    我們先看.class字面量方式,很多人可能不知道這種方式,因為這種用法不是一般java語法。
    通過javap我們可以發(fā)現(xiàn),這種方式的大致等價于定義了一個靜態(tài)成員變量
    ??? static Class class$0;(后面的編號是增長的)
    你可以試圖再定義一個? static Class class$0,應(yīng)該會收到一個編譯錯誤(重復(fù)定義)。
    Class aa=A.class;
    就相當于
    ??? if(class$0==null){
    ?try{
    ?????????? Class.forName("A");
    ?}
    ?cacth(ClassNotFoundException e){
    ??? throw new NoClassDefFoundError(e);
    ?}
    ??? }
    ??? Class aa=class$0;
    可以很清楚的看到,這種類的字面量定義其實不是加載類的方式,而是被編譯器處理了,實質(zhì)
    上是使用了Class.forName方法,但是使用這種方式有一個很大的好處就是不用處理異常,因為
    編譯器處理的時候如果找不到類會拋出一個NoClassDefFoundError。也許你覺得需要處理
    ClassNotFoundException這種異常,事實上99%的情況下我們可以把這種異常認為是一個錯誤。
    所以大部分情況我們使用這種方式會更簡潔。
    最常用的方式就是Class.forName方式了,這也是一個通用的上層調(diào)用。這個方法有兩個重載,
    可能很多人都忽略了第二個方法。
    public static Class forName(String name) throws ClassNotFoundException
    public static Class forName(String name, boolean initialize,ClassLoader loader) throws ClassNotFoundException
    第二個方法后面多了兩個參數(shù),第二個參數(shù)表示是否初始化,第三個參數(shù)為指定的類加載器。
    在上面的例子中:
    Class bb=Class.forName("B");等價于
    Class bb=Class.forName("B",true,Loader.class.getClassLoader());
    這里要詳細說一下這個類的初始化這個參數(shù),如果這個參數(shù)為false的話,
    類中的static成員不會被初始化,static語句塊也不會被執(zhí)行。
    也就是類雖然被加載了,但是沒有被初始化,不過在第一次使用時仍然會初始化。
    所以我們有時候會看到Class.forName("XXX").newInstance()這樣的語句,為什么這里要創(chuàng)建一個
    不用的實例呢?不過是為了保證類被初始化(兼容以前的系統(tǒng))。
    其實第二個方法是比較難用的,需要指定類加載器,如果不指定而且又沒有安裝安全管理器的化,
    是無法加載類的,只要看一下具體的實現(xiàn)就明白了。
    最本質(zhì)的方式當然是直接使用ClassLoader加載了,所有的類最終都是通過ClassLoader加載的,
    Class cc=ClassLoader.getSystemClassLoader().loadClass("C");
    這里通過使用系統(tǒng)類加載器來加載某個類,很直接的方式,但是很遺憾的是通過這種方式加載類,
    類是沒有被初始化的(也就是初始化被延遲到真正使用的時候).不過我們也可以借鑒上面的經(jīng)驗,加載
    后實例化一個對象Class cc=ClassLoader.getSystemClassLoader().loadClass("C").newInstance()。
    這里使用了系統(tǒng)類加載器,也是最常用的類加載器,從classpath中尋找要加載的類。
    java中默認有三種類加載器:引導(dǎo)類加載器,擴展類加載器,系統(tǒng)類加載器。
    java中的類加載有著規(guī)范的層次結(jié)構(gòu),如果我們要了解類加載的過程,需要明確知道哪個類被誰
    加載,某個類加載器加載了哪些類等等,就需要深入理解ClassLoader的本質(zhì)。
    以上只是類加載的表面的東西,我們還將討論深層次的東西。

    原文:http://dev.csdn.net/author/treeroot/a481eb323af84caab1149221432e46b9.html

    posted @ 2006-10-23 16:20 hopeshared 閱讀(905) | 評論 (0)編輯 收藏

         摘要: [文章信息] 作者: cqfz 時間: ...  閱讀全文
    posted @ 2006-10-23 16:19 hopeshared 閱讀(1878) | 評論 (0)編輯 收藏

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

      這篇文章從基礎(chǔ)講起,比如代碼與數(shù)據(jù)的不同之處是什么,他們是如何構(gòu)成一個實例或?qū)ο蟮摹H缓笊钊胩接慾ava虛擬機(

    JVM)是如何利用類加載器讀取代碼,以及java中類加載器的主要類型。接著用一個類加載的基本算法看一下類加載器如何加載一個內(nèi)部類。本文的下一節(jié)演示一段代碼來說明擴展和開發(fā)屬于自己的類加載器的必要性。緊接著解釋如何使用定制的類加載器來完成一個一般意義上的任務(wù),使其可以加載任意遠端客戶的代碼,在JVM中定義,實例化并執(zhí)行它。本文包括了J2EE關(guān)于類加載的規(guī)范——事實上這已經(jīng)成為了J2EE的標準之一。

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

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

      java.lang.Class klass = Myclass.class;

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

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

      類加載器

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

      無論何時我們鍵入java MyMainClass來開始運行一個新的JVM,“引導(dǎo)類加載器(bootstrap class loader)”負責將一些關(guān)鍵的Java類,如java.lang.Object和其他一些運行時代碼先加載進內(nèi)存中。運行時的類在JRE\lib\rt.jar包文件中。因為這屬于系統(tǒng)底層執(zhí)行動作,我們無法在JAVA文檔中找到引導(dǎo)類加載器的工作細節(jié)。基于同樣的原因,引導(dǎo)類加載器的行為在各JVM之間也是大相徑庭。

      同理,如果我們按照如下方式:

      log(java.lang.String.class.getClassLoader());

      來獲取java的核心運行時類的加載器,就會得到null。

      接下來介紹java的擴展類加載器。擴展庫提供比java運行代碼更多的特性,我們可以把擴展庫保存在由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文件或庫文件加入到擴展目錄的classpath,使其可以被擴展類加載器讀取。

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

      Sun的java指南中,文章“理解擴展類加載”(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īng)用程序的類加載器建立。

      類加載器如何工作?

      除了引導(dǎo)類加載器,所有的類加載器都有一個父類加載器,不僅如此,所有的類加載器也都是java.lang.ClassLoader類型。以上兩種類加載器是不同的,而且對于開發(fā)者自訂制的類加載器的正常運行也至關(guān)重要。最重要的方面是正確設(shè)置父類加載器。任何類加載器,其父類加載器是加載該類加載器的類加載器實例。(記住,類加載器本身也是一個類!)

      使用loadClass()方法可以從類加載器中獲得該類。我們可以通過java.lang.ClassLoader的源代碼來了解該方法工作的細節(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());
    ??? }
    }

      第一種方式較為常用,因為通常不建議在構(gòu)造方法里調(diào)用getClass()方法,因為對象的初始化只是在構(gòu)造方法的出口處才完全完成。因此,如果父類加載器被正確建立,當要示從一個類加載器的實例獲得一個類時,如果它不能找到這個類,它應(yīng)該首先去訪問其父類。如果父類不能找到它(即其父類也不能找不這個類,等等),而且如果findBootstrapClass0()方法也失敗了,則調(diào)用findClass()方法。findClass()方法的缺省實現(xiàn)會拋出ClassNotFoundException,當它們繼承java.lang.ClassLoader來訂制類加載器時開發(fā)者需要實現(xiàn)這個方法。findClass()的缺省實現(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é)碼工程庫),它提供了運行時創(chuàng)建類的捷徑。BCEL已經(jīng)被成功地使用在以下方面:編譯器,優(yōu)化器,混淆器,代碼產(chǎn)生器及其他分析工具。一旦字節(jié)碼被檢索,此方法就會調(diào)用defineClass()方法,此行為對不同的類加載實例是有差異的。因此,如果兩個類加載實例從同一個來源定義一個類,所定義的結(jié)果是不同的。

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

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

      Target target3 = (Target) target2;

      以上代碼會拋出一個ClassCastException。這是因為JVM把他們視為分別不同的類,因為他們被不同的類加載器所定義。這種情況當我們不是使用兩個不同的類加載器CustomClassLoader1 和 CustomClassLoader2,而是使用同一個類加載器CustomClassLoader的不同實例時,也會出現(xiàn)同樣的錯誤。這些會在本文后邊用具體代碼說明。

      圖1. 在同一個JVM中多個類加載器加載同一個目標類

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

      為什么我們需要我們自己的類加載器

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

      但是讓我們思考如下情況:我們需要開發(fā)一個通用的執(zhí)行引擎。可以執(zhí)行實現(xiàn)某一特定接口的任何任務(wù)。當任務(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)。把這個兩個存在細微不同的類放在一個classpath下,然后運行Test類:

      set CLASSPATH=.;%CURRENT_ROOT%\v1;%CURRENT_ROOT%\v2

      %JAVA_HOME%\bin\java Test

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

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

      再次運行,類路徑做如下微小改動。

      set CLASSPATH=.;%CURRENT_ROOT%\v2;%CURRENT_ROOT%\v1

      %JAVA_HOME%\bin\java Test

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

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

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

      圖5. AppClassLoader及ExtClassLoader

      繼續(xù)這個例子,文件夾differentversions包含了一個RMI執(zhí)行引擎,客戶端可以提供給執(zhí)行引擎任何實現(xiàn)了common.TaskIntf接口的任務(wù)。子文件夾client1 和 client2包含了類client.TaskImpl有個細微不同的兩個版本。兩個類的區(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ù)實現(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類被加載、實例化,并發(fā)送到服務(wù)端的VM來執(zhí)行。從服務(wù)端的控制臺,可以明顯看到client.TaskImpl代碼只被服務(wù)端的VM執(zhí)行一次,這個單一的代碼版本在服務(wù)端多次生成了許多實例,并執(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)造了許多實例并執(zhí)行。或許客戶端1該不高興了因為并不是它的client.TaskImpl(v1)的方法調(diào)用被服務(wù)端執(zhí)行了,而是其他的一些代碼。如何解決這一問題?答案就是實現(xiàn)定制的類加載器。

      定制類加載器

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

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

      以下是在common.FileSystemClassLoader實現(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)換回代碼。客戶端代碼如下:

    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ù)組定義成類,實例化并執(zhí)行。需要指出的是,對每一個客戶請求,我們用類FileSystemClassLoader的不同實例來定義客戶端提交的client.TaskImpl。而且,client.TaskImpl并不在服務(wù)端的類路徑中。這也就意味著當我們在FileSystemClassLoader調(diào)用findClass()方法時,findClass()調(diào)用內(nèi)在的defineClass()方法。類client.TaskImpl被特定的類加載器實例所定義。因此,當FileSystemClassLoader的一個新的實例被使用,類又被重新定義為字節(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的代碼被多次加載。實際上針對每一個客戶端,類都被加載并初始化。

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

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

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

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

      J2EE的類加載器

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

      結(jié)要

      本文探討了類載入到虛擬機是如何進行唯一標識的,以及類如果存在同樣的類名和包名時所產(chǎn)生的問題。因為沒有一個直接可用的類版本管理機制,所以如果我們要按自己的意愿來加載類時,需要自己訂制類加載器來擴展其行為。我們可以利用許多J2EE服務(wù)器所提供的“熱部署”功能來重新加載一個新版本的類,而不改動服務(wù)器的VM。即使不涉及應(yīng)用服務(wù)器,我們也可以利用定制類加載器來控制java應(yīng)用程序載入類時的具體行為。Ted Neward的書Server-Based Java Programming中詳細闡述java的類加載,J2EE的API以及使用他們的最佳途徑。


    原文:http://searchwebservices.techtarget.com.cn/tips/362/2158862.shtml

    posted @ 2006-10-23 16:16 hopeshared 閱讀(1526) | 評論 (0)編輯 收藏

    僅列出標題
    共30頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
    主站蜘蛛池模板: 国产在线a不卡免费视频| 91热久久免费精品99| 永久黄网站色视频免费| 国产成人精品日本亚洲直接| 巨波霸乳在线永久免费视频| 亚洲国产精品lv| 最近2019年免费中文字幕高清 | 亚洲成?v人片天堂网无码| 黄网站色视频免费观看45分钟| 在线免费观看韩国a视频| 国产亚洲国产bv网站在线| 30岁的女人韩剧免费观看| 亚洲无砖砖区免费| 曰批全过程免费视频在线观看| 国产 亚洲 中文在线 字幕| 免费一区二区三区在线视频| 亚洲国产人成精品| 中文字幕高清免费不卡视频| 国产成人精品日本亚洲| 免费A级毛片无码A∨免费| 色老板亚洲视频免在线观| 国产一级理论免费版| 福利免费在线观看| 亚洲视频在线观看网址| 我想看一级毛片免费的| 阿v视频免费在线观看| 亚洲精品国产精品乱码视色| 亚洲人成免费网站| 久久精品国产亚洲AV| 亚洲女初尝黑人巨高清| 亚洲成av人片在线天堂无| 亚洲精品国产综合久久一线| 精品免费视在线观看| 亚洲一级毛片免费观看| 国产免费啪嗒啪嗒视频看看| 久久久精品免费国产四虎| 亚洲熟女精品中文字幕| 亚洲女同成av人片在线观看 | 美女黄网站人色视频免费国产| 色多多A级毛片免费看| 久久久久久亚洲Av无码精品专口|