如何为Eclipse上的Tomcat配置代码热替换(Hot Code Replacement )

本博客会引导你配置Eclipse的Tomcat的热代码替换(也叫做hotswap debugging)

  • 什么是“热代码替换”
  • 什么是“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中都有支持。

看下如下的代码:

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方法的第一行,并且会以新的代码运行。

什么是“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程序中也可以这么玩儿,但是会有一些问题:

“Hot Code Replace Failed”

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美元,当然了,在天朝,嘿嘿(*^__^*) 。

 

 

转载于:https://my.oschina.net/u/1167449/blog/1523253

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值