如何爲Eclipse上的Tomcat配置代碼熱替換(Hot Code Replacement )

本博客會引導你配置Eclipse的Tomcat的熱代碼替換(也叫作hotswap debugging)java

  • 什麼是「熱代碼替換」
  • 什麼是「JPDA」、「JDI」
  • 基於JPDA的Tomcat的配置
  • 「JPDA」的侷限性——Catch
  • 改進方案1:DCEVM
  • 改進方案2:JRebel

什麼是「熱代碼替換」

「熱代碼替換」(Hot Code Replace,如下簡稱HCR)就是當你正在調試web程序的時候,jvm容許讓你修改的Java代碼馬上生效,而不用重啓程序,HCR是Java Platform Debugger Architecture(JPDA)的一部分(它包含不少東西,好比咱們的遠程調試也是),HCR在現代JVM中都有支持。git

看下以下的代碼:github

public class Sample {
  public static void main(String[] args) {
    String foo = "unchangeable";
    foo += blah();
    System.out.println(foo);
  }
  
  public static String blah() {
    String bar = "bar";
    bar += "blah";
    return bar;
  }
  
}

若是你正在Eclipse中調試這段代碼,你能夠修改它,在線的,而不用重啓程序,好比,在blah方法的第二行打一個斷點,而後調試程序,程序會在bar +=那行掛起,而後修改把字符串「blah」改成「quz」,保存文件,程序會繼續運行,當前行會跳到blah方法的第一行,而且會以新的代碼運行。web

什麼是「JPDA」、「JDI」

簡單來講,Java Platform Debugger Architecture(JPDA)就是Java提供的一套用於開發Java調試工具的規範,任何的JDK實現都須要實現這個規範。數據庫

JDI是這套調試工具提供的API接口,JDI的API在com.sun.jdi包下,至關因而JDI的接口規範了。除了JDK自帶的實現外,我在HotSpot的SA中也發現了一個實現。他倆的實現分別是在com.sun.tools.jdi包下和sun.jvm.hotspot.jdi包下瀏覽器

正是由於有了他們,你才能夠像上面那麼玩兒。緩存

「JPDA」的侷限性——catch

你在基於Tomcat運行的web程序中也能夠這麼玩兒,可是會有一些問題:tomcat

「Hot Code Replace Failed」app

Some code changes cannot be hot swapped into a running virtual machine, such as changing method names or introducing errors into running code. The current target virtual machine was unable to replace It is safe to continue ...框架

而後給你4個按鈕:continue、details、terminate、restart

這個提示應該很眼熟吧,這個叫作Catch。而後剛剛修改的代碼也沒有生效,連行號都不對了。

什麼是Catch?

當咱們在使用HCR的時候仍是有不少限制的:

  1. HCR只能替換方法裏面的代碼
  2. 不能修改類簽名(類名、繼承類、實現接口)、方法簽名(方法名和參數列表)、成員變量
  3. 不能新增類
  4. 特殊的方法調用不能修改,例如main方法,經過反射調用的方法(這些統稱爲「stack frames」)

若是你修改了,那麼上面的錯誤提示就出來了。

基於Tomcat的Web項目配置

配置基於Tomcat的web項目

項目配置,咱們一般能夠按照以下的步驟將web項目部署到Eclipse的Tomcat中:

  1. 下載EE版的Eclipse
  2. 在設置中配置Tomcat。打開設置,找到Servers,而後
  3. 建立Dynamic Web Project
  4. 在Servers視圖中new Server
  5. 右擊建立好的Tomcat,選擇Add And Remove...,將項目部署到Tomcat中
  6. 以Debug模式啓動Tomcat

禁用Auto Reloading

發佈到Tomcat中的項目,默認都是開啓Auto Reloading的,爲了更好地使用JPDA功能,請按照以下步驟禁用Tomcat的Auto Reloading

  1. 雙擊Servers View中的Tomcat。
  2. Services View應該是默認就有的,萬一沒有或者被關閉了,你能夠經過以下方式打開它:菜單:window→show view→services。
  3. 切換到Modules,選中要修改的project,而後點擊edit,去掉「Auto Reloading Enabled」前面的勾。

爲何禁用Auto Reloading

Auto Reloading是一種tomcat用來實現不使用JPDA狀況下支持java類熱替換的。在這種模式下,Tomcat使用java中的classloaders來卸載並從新加載class,當它從新加的時候,tomcat會嘗試從新初始化你的系統,從新啓動那些在web.xml中標記爲load-on-startup的servlet。

結果是,當你的項目裏面有不少的啓動代碼時,這麼作並不會給你節省時間,例如:若是你的啓動代碼須要初始化Hibernate的數據庫緩存,Spring的依賴注入配置等等,你將會花費更長的時間,甚至比重啓tomcat還要長。

更加坑爹的是,被自動加載的程序有時候會變得很奇怪,並且很是容易出現PermGen的內存溢出,這些都是由於頻繁的卸載、從新加載類引發的。當出現這個錯誤的時候,重啓tomcat一般能夠解決這個問題。若是你即便只花費了5分鐘來解決從新加載的問題,你也被坑了,由於原本你期望經過reload來作到比重啓tomcat更省時間的,結果並無。

經過禁用這個「Auto Reloading」來改成使用JPDA的代碼熱替換,你得到了更爲可靠的代碼熱替換。

禁用「Auto Reloading」可是啓用「Auto Publishing」

根據上面說的,你應該知道如何禁用「Auto Reloading」了吧,雖然「Auto Reloading」會致使JPDA工做不正常,可是tomcat的配置頁的「Overview」Tab頁有另外一個設置叫作「Automatically publish when resources change」,它默認是手氣的,你能夠點擊按鈕展開它;當你禁用了「Auto Reloading」之後,這個「Auto Publishing」請確保已經打開。

爲了瞭解二者的區別,咱們須要先了解一下Eclipse的WTP是如何工做的。當你在Eclipse了裏面建立了一個「Server」之後,Eclipse會在你的workspace中建立一個虛擬的Tomcat目錄,這個目錄裏面完整包含了:conf、logs、temp、webapps、works這些目錄,當你配置了這個服務,其實你就告訴了Eclipse去哪兒找tomcat的運行目錄,但並不會使用webapps目錄裏面任何你的配置文件或者數據,在Eclipse啓動tomcat的時候,它將虛擬目錄的位置經過啓動啓動參數的方式傳遞給了jvm。

「發佈(Publishing)」意思就是說將你所有的代碼複製到這個虛擬目錄中,包括:JSP、jar包,配置文件,動態生成的配置等等。

若是你禁用了這個發佈功能,那麼你就須要右擊Server View裏面你的Tomcat,而後點擊「Publish」菜單了,並且每次你保存代碼都要這麼來一遍,更加好的是,若是你開啓了「Auto Publishing」,Tomcat能夠自動就支持JSP的自動從新加載(能夠不用JPDA就能夠支持)。

找到Tomcat虛擬目錄tmp0

不少時候,看下tomcat虛擬目錄的裏面都有什麼東西對咱們代碼開發是很是有幫助的。經過以下方式咱們能夠找到tomcat虛擬目錄:經過雙擊Servers View中的Tomcat,在彈出的頁面中找到Service Locations,咱們就能夠看到了,一般,虛擬目錄在:.metadata/.plugins/org.eclipse.wst.server.core/tmp0,最後一個0是會變的,多個Tomcat的時候會從0開始往上漲。

這個.metadata目錄在你的workspace中(你能夠經過以下方式找到workspace的位置:菜單:FileSwitch Workspace默認的那個就是你當前的workspace),或者,啓動Eclipse的時候讓你選擇的workspace就是你當前的workspace。

在這個虛擬目錄中,你能夠看到全部Eclipse自動建立的目錄,看看conf目錄下的server.xml,檢查一下work目錄下jsp自動生成的java文件,webapps裏面確定是空的,由於Eclipse使用的是wtpwebapps目錄。

改進方案:

上面說了,JPDA有不少的侷限性,可是國外牛人的能力是強大的,咱們能夠經過以下的方式來讓咱們的代碼開發更加高效!

DCEVM

這個是github上的一個開源項目,是國外的一個牛人基於OpenJDK7的源碼從新編寫了其中代碼熱替換部分實現的jvm,經過將咱們默認的Hotspot JVM替換爲此JVM,就能夠自動實現類名修改、方法名修改等一些JPDA不支持的代碼熱替換了。

JRebel

JavaRebel 是一個代碼熱替換系統,它要比HCR好一點 (可能好不少),也能彌補DCEVM對不少web框架不支持的不足。

有了JavaRebel,你能夠在不重啓Tomcat地狀況下增長、刪除方法和類,並且多個project同時運行時不會串,更好的是,它支持對不少框架都加入了支持(Spring、Struts、Jboss等等),好比,你正在基於Spring作代碼開發,新增了一個Controller類或者增長了一個方法(有@RequestMapping),一般狀況下,你須要重啓Tomcat來讓其生效,可是若是你的Eclipse安裝了JavaRebel,那麼當你保存的時候,Controller的信息就所有從新加載了,直接在瀏覽器就能夠訪問對應的URL!

惟一的缺憾就是,它收費,每一個開發人員每一年須要支付149美圓,固然了,在天朝,嘿嘿(*^__^*) 。

相關文章
相關標籤/搜索