38

JRebel 是否使用 Javassist 或某种字节码操作?我问这个纯粹是出于兴趣,我实际上并不“需要”知道:)

4

3 回答 3

49

JRebel 使用类重写(ASM 和 Javassist)和 JVM 集成来对各个类进行版本控制。此外,它还与应用服务器集成以将类/资源和 Web 服务器查找重定向回工作区。它还与大多数应用服务器和框架集成,以将更改传播到配置(元数据或文件)。这就是它的不足之处。需要10位世界级工程师来开发和支持,这是我们的商业秘密:)

于 2011-01-28T13:48:20.973 回答
7

Dave Booth 关于这个主题的精彩文章。重新加载 Java 类:HotSwap 和 JRebel — 幕后

于 2014-09-11T00:32:00.233 回答
7

这是我读到的关于 JRebel 如何工作的最接近ZT 技术传播者 Simon 的推理。

在此处粘贴内容:


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

现在假设用户通过添加一个新方法 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 类的最新版本,因此调用 new C().method1(10) 将在代码更改之前返回 15,之后返回 25。这个实现遗漏了很多细节和优化,但你明白了。

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

于 2015-02-06T08:58:34.377 回答