JRebel如何工作?

JRebel使用Javassist还是某种字节码操作? 我是出于纯粹的兴趣问这个,我其实不需要知道:)

JRebel使用类重写(ASM和Javassist)和JVM集成来版本化单个类。 另外,它还与应用程序服务器集成,将类/资源和Web服务器查找redirect回工作区。 它还与大多数应用程序服务器和框架集成,以传播对configuration(元数据或文件)的更改。 这是它的缺点。 需要10位世界级工程师来开发和支持,这是我们的商业秘密:)

Dave Booth在这个话题上的大文章。 重新加载Java类:HotSwap和JRebel – 幕后花絮 。

ZT技术推广人员Simon对JRebel的工作做了最接近的推理。

在此粘贴内容:


Jrebel使应用程序和JVM类创build一个间接层。 在加载应用程序类的情况下,所有方法体将使用运行时redirect服务进行redirect,如图2所示。该服务使用为每个重新加载的版本创build的匿名内部类来pipe理和加载类和方法版本。 我们来看一个例子。 我们将用两种方法创build一个新的类C:

public class C extends X { int y = 5; int method1(int x) { return x + y; } void method2(String s) { System.out.println(s); } } 

当C类首次被加载时,JRebel将会把这个类join进来。 这个类的签名是一样的,但方法体现在被redirect了。 加载的类现在看起来像这样:

 public class C extends X { int y = 5; int method1(int x) { Object[] o = new Object[1]; o[0] = x; return Runtime.redirect(this, o, "C", "method1", "(I)I"); } void method2(String s) { Object[] o = new Object[1]; o[0] = s; return Runtime.redirect(this, o, "C", "method2", "(Ljava/lang/String;)V"); } } 

对于redirect调用,我们将调用对象,parameter passing给已调用的方法,我们的类名,我们的方法名以及参数的types和返回值。 JRebel还会加载一个类,其中包含特定版本的实现,初始版本为0.让我们看看是什么样的:

 public abstract class C0 { public static int method1(C c, int x) { int tmp1 = Runtime.getFieldValue(c, "C", "y", "I"); return x + tmp1; } public static void method2(C c, String s) { PrintStream tmp1 = Runtime.getFieldValue( null, "java/lang/System", "out", "Ljava/io/PrintStream;"); Object[] o = new Object[1]; o[0] = s; Runtime.redirect(tmp1, o, "java/io/PrintStream;", "println","(Ljava/lang/String;)V"); } } 

现在让我们说用户通过添加一个新的方法z()并从method1调用它来改变他们的类C. C类现在看起来像这样:

 public class C { int y = 5; int z() { return 10; } int method1(int x) { return x + y + z(); } ... } 

下一次运行时使用这个类时,JRebel检测到有一个已经被编译的新版本,并在文件系统上,所以它加载了新版本C1。 此版本具有其他方法z和方法1的更新实现。

 public class C1 { public static int z(C c) { return 10; } public static int method1(C c, int x) { int tmp1 = Runtime.getFieldValue(c, "C", "y", "I"); int tmp2 = Runtime.redirect(c, null, "C", "z", "(V)I"); return x + tmp1 + tmp2; } ... } 

Runtime.redirect调用总是被路由到最新版本的C类,因此调用新的C()。method1(10)将在代码更改之前返回15,之后返回25。 这个实现忽略了很多细节和优化,但是你明白了。

资料来源:http: //zeroturnaround.com/rebellabs/why-hotswap-wasnt-good-enough-in-2001-and-still-isnt-today/