欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Tomcat 熱部署的實(shí)現(xiàn)原理詳解

 更新時(shí)間:2017年01月12日 15:41:44   投稿:lqh  
這篇文章主要介紹了Tomcat 熱部署的實(shí)現(xiàn)原理詳解的相關(guān)資料,需要的朋友可以參考下

Tomcat熱部署機(jī)制

 對(duì)于Java應(yīng)用程序來說,熱部署就是在運(yùn)行時(shí)更新Java類文件。在基于Java的應(yīng)用服務(wù)器實(shí)現(xiàn)熱部署的過程中,類裝入器扮演著重要的角色。大多數(shù)基于Java的應(yīng)用服務(wù)器,包括EJB服務(wù)器和Servlet容器,都支持熱部署。類裝入器不能重新裝入一個(gè)已經(jīng)裝入的類,但只要使用一個(gè)新的類裝入器實(shí)例,就可以將類再次裝入一個(gè)正在運(yùn)行的應(yīng)用程序。

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

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

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

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

Tomcat通過org.apache.jasper.servlet.JasperLoader實(shí)現(xiàn)了對(duì)jsp的加載,

下面做個(gè)測(cè)試:

1. 新建一個(gè)web工程,并編寫一個(gè)jsp頁面,在jsp頁面中輸出該頁面的classloader,.

2. 啟動(dòng)web服務(wù)器,打開jsp頁面,我們可以看到后臺(tái)輸出,該jsp的classloader是JasperLoader的一個(gè)實(shí)例。

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

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

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

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

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

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

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

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

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

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時(shí)或者初次加載時(shí)會(huì)調(diào)用,也就是說在class被再次加載時(shí)會(huì)被調(diào)用,
   * 并且我們通過此方法可以動(dòng)態(tài)修改class字節(jié)碼,實(shí)現(xiàn)類似代理之類的功能,具體方法可使用ASM或者javasist,
   * 如果對(duì)字節(jié)碼很熟悉的話可以直接修改字節(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;
  }
}

以上是基本實(shí)現(xiàn)代碼,需要組件為:

1.HotAgent(預(yù)加載)

 2.ClassTransform(在加載class的時(shí)候可以修改class的字節(jié)碼),本例中沒用到

3.ReloadTask(class定時(shí)加載器,以上代碼僅供參考)

4.META-INF/MANIFEST.MF內(nèi)容為:(參數(shù)一:支持class重定義;參數(shù)二:預(yù)加載類)

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

5.將以上組件打包成jar文件(到此,組件已經(jīng)完成,下面為編寫測(cè)試類文件)。

6.新建一個(gè)java工程,編寫一個(gè)java邏輯類,并編寫一個(gè)Test類,在該測(cè)試類中調(diào)用邏輯類的方法,

下面看下測(cè)試類代碼:

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);
    }
  }
}

運(yùn)行測(cè)試類:

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

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

Tomcat 熱部署配置

<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  title="Eclipse ImportNew主頁" target="_blank">Eclipse</a></span>.jst.j2ee.server:CPCWeb"/>
</Host>

autoDeploy=”true” — 自動(dòng)部署 reloadable=”true” — 自動(dòng)加載

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • 替換或重寫Tomcat內(nèi)置的404頁面的方法

    替換或重寫Tomcat內(nèi)置的404頁面的方法

    這篇文章主要介紹了替換或重寫Tomcat內(nèi)置的404頁面的方法,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-09-09
  • 解決Tomcat 中catalina.out持續(xù)累加問題

    解決Tomcat 中catalina.out持續(xù)累加問題

    這篇文章主要介紹了解決Tomcat 中catalina.out持續(xù)累加問題 ,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-03-03
  • 如何將tomcat源碼以maven方式運(yùn)行

    如何將tomcat源碼以maven方式運(yùn)行

    這篇文章主要介紹了如何將tomcat源碼以maven方式運(yùn)行,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 親測(cè)有效解決Tomcat啟動(dòng)提示錯(cuò)誤:At?least?one?JAR?was?scanned?for?TLDs?yet?contained?no?TLDs

    親測(cè)有效解決Tomcat啟動(dòng)提示錯(cuò)誤:At?least?one?JAR?was?scanned?for?T

    這篇文章主要介紹了Tomcat啟動(dòng)提示錯(cuò)誤:At?least?one?JAR?was?scanned?for?TLDs?yet?contained?no?TLDs的問題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • 詳解tomcat各個(gè)端口的作用

    詳解tomcat各個(gè)端口的作用

    這篇文章主要介紹了詳解tomcat各個(gè)端口的作用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Tomcat配置及如何在Eclipse中啟動(dòng)

    Tomcat配置及如何在Eclipse中啟動(dòng)

    這篇文章主要介紹了Tomcat配置及如何在Eclipse中啟動(dòng),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • 關(guān)于Tomcat?結(jié)合Atomikos?實(shí)現(xiàn)JTA的方法

    關(guān)于Tomcat?結(jié)合Atomikos?實(shí)現(xiàn)JTA的方法

    Tomcat作為一款經(jīng)典的Web服務(wù)器,在開發(fā)、測(cè)試和生產(chǎn)環(huán)境中得到了廣泛的使用。但Tomcat畢竟不是Java EE服務(wù)器,因此在EJB,JTA方面并沒有提供支持。本文講述了Tomcat使用Atomikos實(shí)現(xiàn)JTA的一種方法,需要的朋友可以參考下
    2021-11-11
  • 淺析Tomcat使用線程池配置高并發(fā)連接

    淺析Tomcat使用線程池配置高并發(fā)連接

    這篇文章主要介紹了Tomcat使用線程池配置高并發(fā)連接,文中提到了tomcat內(nèi)存優(yōu)化,tomcat內(nèi)存優(yōu)化主要是對(duì)?tomcat?啟動(dòng)參數(shù)優(yōu)化,我們可以在?tomcat?的啟動(dòng)腳本?catalina.sh?中設(shè)置JAVA_OPTS?參數(shù),需要的朋友可以參考下
    2022-10-10
  • Tomcat配置SSL證書的方法

    Tomcat配置SSL證書的方法

    這篇文章主要介紹了Tomcat配置SSL證書的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • 解析Tomcat的啟動(dòng)腳本--catalina.bat

    解析Tomcat的啟動(dòng)腳本--catalina.bat

    本文主要對(duì)Tomcat的三個(gè)最重要的啟動(dòng)腳本之一--catalina.bat腳本做了詳細(xì)分析,具有很好的參考價(jià)值,需要的朋友可以看下
    2016-12-12

最新評(píng)論