JRebel如何运作?

时间:2011-01-28 10:05:23

标签: jrebel

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

3 个答案:

答案 0 :(得分:47)

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

答案 1 :(得分:6)

Dave Booth关于这个主题的精彩文章。 Reloading Java Classes: HotSwap and JRebel — Behind the Scenes

答案 2 :(得分:5)

这是我读过ZT技术布道师Simon的JRebel works的最接近的推理。

在此处粘贴内容:


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/