日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > 服務(wù)器 > Tomcat系列(一)Tomcat熱部署的實(shí)現(xiàn)原理

Tomcat系列(一)Tomcat熱部署的實(shí)現(xiàn)原理

來源:程序員人生   發(fā)布時間:2017-03-09 09:12:19 閱讀次數(shù):5852次

Tomcat熱部署機(jī)制

對Java利用程序來講,熱部署就是在運(yùn)行時更新Java類文件。在基于Java的利用服務(wù)器實(shí)現(xiàn)熱部署的進(jìn)程中,類裝入器扮演側(cè)重要的角色。大多數(shù)基于Java的利用服務(wù)器,包括EJB服務(wù)器和Servlet容器,都支持熱部署。類裝入器不能重新裝入1個已裝入的類,但只要使用1個新的類裝入器實(shí)例,就能夠?qū)㈩愒俅窝b入1個正在運(yùn)行的利用程序。

我們知道,現(xiàn)在大多數(shù)的web服務(wù)器都支持熱部署,而對熱部署的實(shí)現(xiàn)機(jī)制,網(wǎng)上講的卻不夠完善,下面我們就Tomcat的熱部署實(shí)現(xiàn)機(jī)制,講授1下它是如何實(shí)現(xiàn)的:

Tomcat的容器實(shí)現(xiàn)熱部署使用了兩種機(jī)制:

Classloader重寫,通過自定義classloader加載相應(yīng)的jsp編譯后的class到JVM中。 通過動態(tài)修改內(nèi)存中的字節(jié)碼,將修改過的class再次裝載到JVM中。

Classloader實(shí)現(xiàn)jsp的重新加載

Tomcat通過org.apache.jasper.servlet.JasperLoader實(shí)現(xiàn)了對jsp的加載,下面做個測試: 1. 新建1個web工程,并編寫1個jsp頁面,在jsp頁面中輸出該頁面的classloader,<%System.out.print(this.getClass().getClassLoader());%>.

2. 啟動web服務(wù)器,打開jsp頁面,我們可以看到后臺輸出,該jsp的classloader是JasperLoader的1個實(shí)例。

3. 修改jsp,保存并刷新jsp頁面,再次查看后臺輸出,此classloader實(shí)例已不是剛才那個了,也就是說tomcat通過1個新的classloader再次裝載了該jsp。

4. 其實(shí),對每一個jsp頁面tomcat都使用了1個獨(dú)立的classloader來裝載,每次修改完jsp后,tomcat都將使用1個新的classloader來裝載它。

關(guān)于如何使用自定義classloader來裝載1個class這里就不說了,相信網(wǎng)上都能找到,JSP屬于1次性消費(fèi),每次調(diào)用容器將創(chuàng)建1個新的實(shí)例,屬于用完就扔的那種,但是對這類實(shí)現(xiàn)方式卻很難用于其它情況下,如現(xiàn)在我們工程中很多都使用了單例,特別是spring工程,在這類情況下使用新的classloader來加載修改后的類是不現(xiàn)實(shí)的,單例類將在內(nèi)存中產(chǎn)生多個實(shí)例,而且這類方式?jīng)]法改變當(dāng)前內(nèi)存中已有實(shí)例的行動,固然,tomcat也沒通過該方式實(shí)現(xiàn)class文件的重新加載。

通過代理修改內(nèi)存中class的字節(jié)碼

Tomcat中的class文件是通過org.apache.catalina.loader. WebappClassLoader裝載的,一樣我們可以做個測試,測試進(jìn)程與jsp測試類似,測試步驟就不說了,只說1下結(jié)果:

在熱部署的情況下,對被該classloader 加載的class文件,它的classloader始終是同1個WebappClassLoader,除非容器重啟了,相信做完這個實(shí)驗(yàn)?zāi)憔筒粫僬J(rèn)為tomcat是使用1個新的classloader來加載修改過的class了,而且對有狀態(tài)的實(shí)例,之前該實(shí)例具有的屬性和狀態(tài)都將保存,并在下次履行時具有了新的class的邏輯,這就是熱部署的神秘的地方(其實(shí)每一個實(shí)例只是保存了該實(shí)例的狀態(tài)屬性,我們通過序列化對象就可以看到對象中包括的狀態(tài),終究的邏輯還是存在于class文件中)。

下面的class重定義是通過:java.lang.instrument實(shí)現(xiàn)的,具體可參考相干文檔。

下面我們看1下如何通過代理修改內(nèi)存中的class字節(jié)碼:

以下是1個簡單的熱部署代理實(shí)現(xiàn)類(代碼比較粗糙,也沒甚么判斷):

復(fù)制代碼
package agent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.util.Set;
import java.util.Timer;
import java.util.TreeSet;
public  class  HotAgent {
 
    protected  static  Set<String>  clsnames=new TreeSet<String>();
 
    public  static  void  premain(String  agentArgs, Instrumentation  inst)  throws Exception {
        ClassFileTransformer  transformer =new ClassTransform(inst);
        inst.addTransformer(transformer);
        System.out.println("是不是支持類的重定義:"+inst.isRedefineClassesSupported());
        Timer  timer=new  Timer();
        timer.schedule(new ReloadTask(inst),2000,2000);
    }
}

package agent;
import java.lang.instrument.ClassFileTransformer;
importjava.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
 
public  class  ClassTransform.  implements ClassFileTransformer {
    private  Instrumentation  inst;
 
    protected  ClassTransform(Instrumentation  inst){
        this.inst=inst;
    }
 
    /**
     * 此方法在redefineClasses時或初次加載時會調(diào)用,也就是說在class被再次加載時會被調(diào)用,
     * 并且我們通過此方法可以動態(tài)修改class字節(jié)碼,實(shí)現(xiàn)類似代理之類的功能,具體方法可以使用ASM或javasist,
     * 如果對字節(jié)碼很熟習(xí)的話可以直接修改字節(jié)碼。
     */
    public  byte[]  transform(ClassLoader  loader, String  className,
           Class<?>  classBeingRedefined, ProtectionDomain  protectionDomain,
           byte[]  classfileBuffer)throws IllegalClassFormatException {
        byte[]  transformed = null;
        HotAgent.clsnames.add(className);
        return  null;
    }
}

package agent;
import java.io.InputStream;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.util.TimerTask;
 
public  class  ReloadTask  extends  TimerTask {
    private  Instrumentation  inst;
 
    protected  ReloadTask(Instrumentation  inst){
        this.inst=inst;
    }
 
    @Override
    public  void  run() {
       try{
           ClassDefinition[]  cd=new ClassDefinition[1];
           Class[]  classes=inst.getAllLoadedClasses();
           for(Class  cls:classes){
                if(cls.getClassLoader()==null||!cls.getClassLoader().getClass().getName().equals("sun.misc.Launcher$AppClassLoader"))
                    continue;
                String  name=cls.getName().replaceAll("\\.","/");
                cd[0]=new ClassDefinition(cls,loadClassBytes(cls,name+".class"));
                inst.redefineClasses(cd);
           }
       }catch(Exception ex){
            ex.printStackTrace();
       }
    }
 
    private  byte[]  loadClassBytes(Class  cls,String  clsname) throws  Exception{
        System.out.println(clsname+":"+cls);
        InputStream  is=cls.getClassLoader().getSystemClassLoader().getResourceAsStream(clsname);
        if(is==null)return  null;
        byte[]  bt=new  byte[is.available()];
        is.read(bt);
        is.close();
        return  bt;
    }
}
復(fù)制代碼

 

以上是基本實(shí)現(xiàn)代碼,需要組件為: 1.HotAgent(預(yù)加載) 2.ClassTransform(在加載class的時候可以修改class的字節(jié)碼),本例中沒用到 3.ReloadTask(class定時加載器,以上代碼僅供參考) 4.META-INF/MANIFEST.MF內(nèi)容為:(參數(shù)1:支持class重定義;參數(shù)2:預(yù)加載類)

Can-Redefine-Classes: true Premain-Class: agent.HotAgent

5.將以上組件打包成jar文件(到此,組件已完成,下面為編寫測試類文件)。 6.新建1個java工程,編寫1個java邏輯類,并編寫1個Test類,在該測試類中調(diào)用邏輯類的方法,下面看下測試類代碼:

 

復(fù)制代碼
package test.redefine;
 
public  class  Bean1 {
    public  void  test1(){
      System.out.println("============================");
    }
}

package test.redefine;
 
public  class  Test {
    public  static  void  main(String[] args)throws  InterruptedException {
 
       Bean1  c1=new  Bean1();
       while(true){
           c1.test1();
           Thread.sleep(5000);
       }
    }
}
復(fù)制代碼

運(yùn)行測試類:

java –javaagent:agent.jar test.redefine.Test

在測試類中,我們使用了1個死循環(huán),定時調(diào)用邏輯類的方法。我們可以修改Bean1中的方法實(shí)現(xiàn),將在不同時間看到不同的輸出結(jié)果,關(guān)于技術(shù)細(xì)節(jié)也沒甚么好講的了,相信大家都能明白。

Tomcat 熱部署配置

 

復(fù)制代碼
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">  
    <Context docBase="CPCWeb" path="/CPCWeb" reloadable="true" source="org.<span class="wp_keywordlink"><a href="http://res.importnew.com/eclipse" title="Eclipse ImportNew主頁" target="_blank">Eclipse</a></span>.jst.j2ee.server:CPCWeb"/>
</Host>


復(fù)制代碼

autoDeploy=”true” — 自動部署 reloadable=”true” — 自動加載

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 视频免费1区二区三区 | 久久爱综合网 | 亚洲永久网站 | 亚洲一区二区三区在线免费观看 | av免费播放 | 久久久国产精品 | 国产一区在线播放 | 97在线观看视频 | 中文字幕av网 | 国产一区免费视频 | 亚洲一区二区三区中文字幕 | 成人午夜在线视频 | 久久不射网站 | 欧美综合在线观看 | 最新国产精品视频 | 欧美在线激情 | 精品欧美一区二区三区免费观看 | 男人av在线 | 欧美 日韩 国产 成人 在线 | 国产伦精品一区二区三区四区免费 | 国产精品国产精品 | 成人高清在线 | 免费黄色小视频 | 欧美日韩精品在线观看 | 久www| 国产一区二区三区网站 | 久久99精品久久久久久久久久久久 | 久久国产精品99久久久久久老狼 | 高清av网站 | 日本不卡一区二区三区在线观看 | 日韩美女一区 | 久久免费视频观看 | 在线三区 | 欧美精品www| 婷婷六月色 | 亚久久| 亚洲精品视频一区二区 | 久久久久久一区 | 国产91久久精品一区二区 | 欧美日韩一区在线观看 | 免费a级人成a大片在线观看 |