当我发现通过普通的agent技术只能实现“方法体内的代码替换”,于是开始在网上寻找新技术能较好的解决热替换的问题,第1个发现的便是已经比较成熟的工具dcevm
(1)dcevm工具
现在的jvm不是只支持“方法内的代码替换”吗,dcevm便霸气的改了jvm,其安装工具也就是直接替换jdk下面的jvm.dll。听起来是不是很可怕很不靠谱,jvm这么底层的东西也是能动的?先前我向同事分享这个工具的时候,他们第一反映也是这样。。。
但dcevm的实际使用起来还是不错的,并且官网文档一直在强调推荐使用在开发环境和测试环境,并不推荐使用在生产环境。(dcevm的定位非常务实)
dcevm是开源的,不过因为部分原因没拿到代码,这里就做一下工具的调试
首先写一个很简单的例子,循环定时打印“hello world”
class SimplePrinter {
SimplePrinter(){}
void print(){
System.out.println("hello world");
}
}
public class Main {
public static void main(String[] args){
while(true){
try {
SimplePrinter clazz = new SimplePrinter();
clazz.print();
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行结果如下:(一定要调试运行,调试才会开启eclipse的热替换功能)
hello world
hello world
hello world
hello world
我们先做1个尝试,在simpleprinter的print方法中多加1个打印信息
class SimplePrinter {
SimplePrinter(){}
void print(){
System.out.println("hello world");
System.out.println("changed in method");
}
}
保存后,会发现控制台打印的内容变了
hello world
hello world
changed in method
hello world
changed in method
我们再做另外一次尝试,在simplePrinter中新增一个方法并调用,如下
class SimplePrinter {
SimplePrinter(){}
void print(){
System.out.println("hello world");
System.out.println("changed in method");
newMethod();
}
void newMethod(){
System.out.println("new method");
}
}
点击保存,会弹如下的对话框
关键字是“hotcode replace failed”,在网上查了些资料,并用git拉了eclipse的源代码看了下,知道了eclipse里实现的“热替换”叫“hotcode”,是集成在其调试模块的。eclipse里面使用的是自带的sun/…/tools.jar包(具体路径忘了),不同于我们先前使用的jdk/lib/tools.jar包,记得应该是一样的。这就意味着eclipse支持的“热替换”也只支持“方法内的代码热替换”,从我们先前的例子也可以得出。
于是,就需要更强大的“热替换工具”了,我们先试试dcevm
其安装过程很简单,前面也介绍过,dcevm安装过程就是把修改后的jvm.dll替换你本机上jdk下面的jvm.dll,这个安装实现很简单,难的是dcevm是怎么修改jvm得到优化后的jvm.dll的,好在我们不用讨论这个问题。。。
选择使用的jdk进行替换,我们再来试一下上面的测试例子
(2)jrebel工具
相比dcevm工具的直接,jrebel在java层面解决了“热替换”的问题。在网上查资料的过程中,很多网友盛赞了jrebel,赞其在线上环境真的解决了很多问题。不过jrebel是收费,不知道他们是不是用的“破解版”。。。
心痒难耐,下了个试用版试试。
jrebel似乎是为web应用量身制作的,从网上看的资料似乎可以和tomcat很好的集成。对于非web项目也有相应的解决方案。我先下了个jrebel的eclipse插件版在开发环境体验,如果不错发现可以引进项目的话,在linux环境下可以使用shell命令运行。不错
体验工具总是很简单的,想探究jrebel的原理就比较难了,似乎不是自己技术水平可以做的事。好在jrebel作者大方的再几篇博客中谈及了一下jrebel的实现原理,可以想象一下。。。