JRebel是如何工作的?

问题描述 投票:38回答:3

JRebel是使用Javassist还是某种字节码操作?我问这个问题完全是出于兴趣,实际上我并不 "需要 "知道:)

jrebel
3个回答
48
投票

JRebel使用类重写(包括ASM和Javassist)和JVM集成来对单个类进行版本调整。另外,它还与应用服务器集成,将classresource和web服务器的查找重定向回工作空间。而且它还与大多数应用服务器和框架集成,以传播对配置(元数据或文件)的更改。这就是它的短处。它的长处是需要10个世界级的工程师来开发和支持,并且是我们的商业机密 :)


7
投票

这是我读到的最接近JRebel的推理。作品 作者:西蒙,ZT技术布道者。

把内容粘贴在这里。


Jrebel对应用程序和JVM类进行工具化处理,以创建一层重定向。在应用类被加载的情况下,所有方法体都会有一个使用运行时重定向服务的重定向,如图2所示。这个服务使用为每个被重载的版本创建的匿名内部类来管理和加载类和方法的版本。我们来看一个例子。我们将创建一个具有两个方法的新类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会对该类进行文书处理。这个类的签名将是相同的,但是方法体现在被重定向了。加载后的类现在看起来是这样的。

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

为了重定向调用,我们传递了调用对象, 被调用的方法的参数,我们的类名,我们的方法名 以及参数和返回的类型。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");
 }
}

假设用户改变了他们的C类,增加了一个新的方法z() 并从方法1中调用它。 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.重定向调用总是会被路由到类C的最新版本,所以调用new C().method1(10)会在代码更改前返回15,更改后返回25。这个实现错过了很多细节和优化,但你明白了。

来源于:http:/zeroturnaround http:/zeroturnaround.comrebellabswhy-hotswap-wasnt-good-enough-in-2001-and-still-isnt-today。


7
投票

Dave Booth写的关于这个主题的好文章。重新加载Java类。HotSwap和JRebel--幕后花絮.

© www.soinside.com 2019 - 2024. All rights reserved.