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

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

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

    posts - 495,comments - 227,trackbacks - 0
    tomcat的reloadable參數(shù)的意思
    開(kāi)啟了Tomcat的reloadable=true,那么每當(dāng)相關(guān)文件改變時(shí),Tomcat會(huì)停止web app并釋放內(nèi)存,然后重新加載web app.這實(shí)在是個(gè)浩大的工程。
           另外網(wǎng)上有一篇文章是關(guān)于在Tomcat運(yùn)行動(dòng)態(tài)重載類(lèi),下面是該文章的內(nèi)容
            
    1. 為什么寫(xiě)這篇文檔?

    使 用過(guò)hibernate, spring或其他大型組件,寫(xiě)過(guò)50個(gè)類(lèi)以上的網(wǎng)絡(luò)應(yīng)用程序(web application)的開(kāi)發(fā)者應(yīng)該知道,當(dāng)系統(tǒng)中有很多類(lèi)時(shí),如果開(kāi)啟了Tomcat的reloadable=true,那么每當(dāng)相關(guān)文件改變 時(shí),Tomcat會(huì)停止web app并釋放內(nèi)存,然后重新加載web app.這實(shí)在是個(gè)浩大的工程。

    所以我總是在想如果能有只重載某幾個(gè)類(lèi)的功能,將極大的滿(mǎn)足我這個(gè)即時(shí)調(diào)試狂。

    去年我在論壇上發(fā)帖,才發(fā)現(xiàn)已經(jīng)有一些應(yīng)用服務(wù)器具有了這個(gè)功能,比如WebLogic, WebSphere, 等等。好像還有一個(gè)很酷的名字,叫開(kāi)發(fā)模式。看來(lái)我還是孤陋寡聞了點(diǎn)。

    當(dāng)然很多人都是在Tomcat上開(kāi)發(fā),包括我。我很喜歡它的輕小,那些大內(nèi)存和高CPU消耗的應(yīng)用服務(wù)器不愧為硬件殺手,沒(méi)理由不改進(jìn)Tomcat :)。

    1. 最終實(shí)現(xiàn)功能

    我沒(méi)有時(shí)間去研究Tomcat的文件監(jiān)聽(tīng)機(jī)制,也沒(méi)時(shí)間去把他寫(xiě)成”開(kāi)發(fā)模式”這么完整的功能,我最終實(shí)現(xiàn)的是,實(shí)現(xiàn)重載功能的測(cè)試jsp--很抱歉我還是沒(méi)辦法寫(xiě)得更完整。當(dāng)然,你可以在這個(gè)基礎(chǔ)上進(jìn)行改進(jìn)。

    1. 閱讀須知

    閱讀本文,你應(yīng)該具備以下知識(shí)

      1. jvm 規(guī)范有關(guān)類(lèi)加載器的章節(jié)

        http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html

      2. Tomcat 類(lèi)加載機(jī)制

        http://www.huihoo.org/apache/tomcat/

      3. java 反射機(jī)制

        http://java.sun.com/docs/books/tutorial/reflect/

      4. ant

        http://ant.apache.org/

        (好象該網(wǎng)址被不定時(shí)封鎖,有時(shí)能上,有時(shí)不能)

    最好在你的電腦上安裝ant,因?yàn)門(mén)omcat源碼包使用ant從互聯(lián)網(wǎng)獲得依賴(lài)包。不過(guò)我也是修改了一個(gè)錯(cuò)誤才使它完全編譯通過(guò)。

    當(dāng)然,你也可以用其他IDE工具檢查并添加依賴(lài)包,在IDE中,其實(shí)你只需要添加jar直到使org.apache.catalina.loader.WebappClassLoader無(wú)錯(cuò)即可。

    1. 修改過(guò)程

      1. 說(shuō)明

    新添加的代碼請(qǐng)?zhí)砑拥絡(luò)ava文件的末尾,因?yàn)槲以谡f(shuō)明行數(shù)的時(shí)候,盡量符合原始行數(shù)

      1. web app類(lèi)加載器

    在Tomcat中,org.apache.catalina.loader.WebappClassLoader是web app的類(lèi)加載器,所以需要修改它實(shí)現(xiàn)重載功能。

      1. 資源列表

    在WebappClassLoader中,有一個(gè)Map類(lèi)型屬性resourceEntries,它記載了web app中WEB-INF/classes目錄下所加載的類(lèi),因此當(dāng)我們需要重載一個(gè)類(lèi)時(shí),我們需要先將它在resourceEntries里刪除,我編寫(xiě)了一個(gè)方法方便調(diào)用:

    public boolean removeResourceEntry(String name) {

         if (resourceEntries.containsKey(name)) {

             resourceEntries.remove(name);

             return true;

         }

         return false;

    }

      1. 是否重載標(biāo)志

    讓W(xué)ebappClassLoader需要知道加載一個(gè)類(lèi)是否使用重載的方式。所以我建立一個(gè)boolean 類(lèi)型的屬性和實(shí)現(xiàn)它的getter/setter方法:

    private boolean isReload = false;


          public boolean isReload() {

              return isReload;

          }


          public void setReload(boolean isReload) {

              this.isReload = isReload;

          }

      1. 動(dòng)態(tài)類(lèi)加載器

    根據(jù)jvm類(lèi)加載器規(guī)范,一個(gè)類(lèi)加載器對(duì)象只能加載一個(gè)類(lèi)1次,所以重載實(shí)際上是創(chuàng)建出另一個(gè)類(lèi)加載器對(duì)象來(lái)加載同一個(gè)類(lèi)。當(dāng)然,我們不需要再創(chuàng)建一個(gè)WebappClassLoader,他太大而且加載規(guī)則很復(fù)雜,不是我們想要的,所以我們創(chuàng)建一個(gè)簡(jiǎn)單的類(lèi)加載器類(lèi)org.apache.catalina.loader.DynamicClassLoader:

    package org.apache.catalina.loader;


    import java.net.URL;

    import java.net.URLClassLoader;

    import java.security.CodeSource;

    import java.util.*;


    /**

    * 動(dòng)態(tài)類(lèi)加載器

    *

    @author peter

    *

    */

    public class DynamicClassLoader extends URLClassLoader {

        /* 父類(lèi)加載器 */

        private ClassLoader parent = null;


        /* 已加載類(lèi)名列表 */

        private List classNames = null;


        /**

        * 構(gòu)造器

        *

        * @param parent

        * 父類(lèi)加載器,這里傳入的是WebappClassLoader

        */

        public DynamicClassLoader(ClassLoader parent) {

            super(new URL[0]);

            classNames = new ArrayList();

            this.parent = parent;

        }


        /**

        * 從類(lèi)的二進(jìn)制數(shù)據(jù)中加載類(lèi).

        *

        * @param name

        * 類(lèi)名

        * @param classData

        * 類(lèi)的二進(jìn)制數(shù)據(jù)

        * @param codeSource

        * 數(shù)據(jù)來(lái)源

        * @return 成功加載的類(lèi)

        * @throws ClassNotFoundException

        * 加載失敗拋出未找到此類(lèi)異常

        */

        public Class loadClass(String name, byte[] classData, CodeSource codeSource) throws ClassNotFoundException {

            if (classNames.contains(name)) {

                // System.out.println("此類(lèi)已存在,調(diào)用 loadClass 方法加載.");

                return loadClass(name);

            } else {

                // System.out.println("新類(lèi), 記錄到類(lèi)名列表,并用類(lèi)定義方法加載類(lèi)");

                classNames.add(name);

                return defineClass(name, classData, 0, classData.length, codeSource);

            }

        }


        /* *

        * 重載此方法,當(dāng)要加載的類(lèi)不在類(lèi)名列表中時(shí),調(diào)用父類(lèi)加載器方法加載.

        * @see java.lang.ClassLoader#loadClass(java.lang.String)

        */

        public Class loadClass(String name) throws ClassNotFoundException {

            if (!classNames.contains(name)) {

                //System.out.println("不在類(lèi)名列表中,調(diào)用父類(lèi)加載器方法加載");

                return parent.loadClass(name);

            }

            return super.loadClass(name);

        }

    }

      1. 在webappClassLoader中添加DynamicClassLoader

        1. 添加屬性

    private DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this);

        1. 添加重建方法,以便需要再次重載時(shí)替換掉上次的類(lèi)加載器對(duì)象

    public void reCreateDynamicClassLoader() {

                    dynamicClassLoader = new DynamicClassLoader(this);

                }

      1. 修改調(diào)用點(diǎn)

        1. 第832行,公開(kāi)findClass方法

    public Class findClass(String name) throws ClassNotFoundException {

        1. 第1569行,添加如下一行代碼。

    if (isReload) removeResourceEntry(name);

        1. 第1577行,這里好像是一個(gè)bug,具體原因我忘了-_-||

    if ((entry == null) || (entry.binaryContent == null))

    改為

    if ((entry == null) || (entry.loadedClass == null && entry.binaryContent == null))

        1. 第1633~1636行

    if (entry.loadedClass == null) {

                    clazz = defineClass(name, entry.binaryContent, 0, entry.binaryContent.length,

                        codeSource);

                改為

                byte[] classData = new byte[entry.binaryContent.length];

                System.arraycopy(entry.binaryContent, 0, classData, 0,

                classData.length);

                if (entry.loadedClass == null) {

                    clazz = isReload ?

                        dynamicClassLoader.loadClass(name,

                        classData, codeSource) :

                        defineClass(name,

                        classData, 0, classData.length, codeSource);

      1. 測(cè)試代碼

        1. test.jsp

    我測(cè)試用的jsp為$CATALINA_HOME/webapps/ROOT/test.jsp,由于webapp里面并不會(huì)顯式加載tomcat的核心類(lèi),所以我們需要用反射代碼調(diào)用WebappClassLoader的方法。代碼如下:

    <%

    ClassLoader loader = (Thread.currentThread().getContextClassLoader());

    Class clazz = loader.getClass();

    java.lang.reflect.Method setReload = clazz.getMethod("setReload", new Class[]{boolean.class});

    java.lang.reflect.Method reCreate = clazz.getMethod("reCreateDynamicClassLoader", null);

    java.lang.reflect.Method findClass = clazz.getMethod("findClass", new Class[]{String.class});

    reCreate.invoke(loader, null);

    setReload.invoke(loader, new Object[]{true});

    Class A = (Class)findClass.invoke(loader, new Object[]{"org.AClass"});

    setReload.invoke(loader, new Object[]{false});

    A.newInstance();

    // 如果你使用下面這行代碼,當(dāng)重編譯類(lèi)時(shí),請(qǐng)稍微修改一下調(diào)用它的jsp,讓jsp也重新編譯

    //org.AClass a = (org.AClass)A.newInstance();

    // 下面這些代碼是測(cè)試當(dāng)一個(gè)類(lèi)不在DynamicClassLoader類(lèi)名列表時(shí)的反應(yīng)

    //a.test();

    //java.lang.reflect.Method test = a.getClass().getMethod("test", null);

    //test.invoke(a, null);

    %>

        1. org.AClass

    package org;


            public class AClass {

                public AClass() {

                    // 修改輸出內(nèi)容確認(rèn)Tomcat重新加載了類(lèi)

                    System.out.println("AClass v3");

                }


                public void createBClass() {

                    new BClass();

                }

            }

        1. org.BClass

    package org;


            public class BClass {

                public BClass() {

                    //修改輸出內(nèi)容確認(rèn)Tomcat重新加載了類(lèi)

                    System.out.println("BClass v1");

                }

            }

      1. 測(cè)試步驟

        1. 按照上述步驟修改Tomcat源碼并編譯。

        2. 用winzip/winrar/file-roller打開(kāi)$CATALINA_HOME/server/lib/catalina.jar。把前面編譯完成后的org.apache.catalina.loader目錄下的class文件覆蓋jar中同名文件。

        3. 編譯org.AClass和org.BClass

        4. 啟動(dòng)Tomcat并在瀏覽器中打開(kāi)測(cè)試頁(yè)http://localhost:8080/test.jsp

        5. 修改org.AClass中的System.out.println();語(yǔ)句并重編譯類(lèi)。

        6. 按下F5按鍵刷新瀏覽器。

        7. 查看Tomcat控制臺(tái)是否輸出了不同的語(yǔ)句?

        8. Good Luck! :)))

    posted on 2011-05-31 16:55 SIMONE 閱讀(21248) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): JAVAtomcat
    主站蜘蛛池模板: 99re在线免费视频| 无人影院手机版在线观看免费| 又黄又爽又成人免费视频| 国产精品二区三区免费播放心 | 内射无码专区久久亚洲| 久久久久亚洲AV片无码| 亚洲人成人网站18禁| 热久久这里是精品6免费观看| 三年片在线观看免费大全| 在线日韩日本国产亚洲| ww亚洲ww在线观看国产| 久久精品无码专区免费| 成人片黄网站A毛片免费| 亚洲中文字幕无码日韩| 亚洲午夜无码久久久久小说| 成人久久免费网站| 国产网站在线免费观看| 久久久无码精品亚洲日韩京东传媒| 色网站在线免费观看| 四虎成年永久免费网站| 久久亚洲中文字幕精品一区| 亚洲日韩一区精品射精| 无码人妻AV免费一区二区三区| 又色又污又黄无遮挡的免费视| 亚洲另类春色校园小说| 中国国语毛片免费观看视频| 日韩免费三级电影| 亚洲毛片无码专区亚洲乱| 全黄大全大色全免费大片| 国产亚洲精品免费| 色老板亚洲视频免在线观| 免费一级不卡毛片| 亚洲AV网站在线观看| 亚洲AV无码乱码在线观看代蜜桃| 免费网站观看WWW在线观看| 免费国产成人高清在线观看麻豆| 亚洲一卡2卡4卡5卡6卡残暴在线| 国产猛男猛女超爽免费视频| 亚洲国产成人久久精品99| 亚洲第一成人在线| 1000部免费啪啪十八未年禁止观看 |