JRebel如何运作?

Zub*_*air 37 jrebel

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

Jev*_*nov 47

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

  • @Dexter确实如此 (3认同)
  • @Jevgeni Kabanov:JRebel是否处理最终类的重新加载? (2认同)

cze*_*rny 6

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


Jat*_*tin 6

这是我对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);
 }
}
Run Code Online (Sandbox Code Playgroud)

当第一次加载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");
 }
}
Run Code Online (Sandbox Code Playgroud)

对于重定向调用,我们传入调用对象,将参数传递给已调用的方法,我们的类名,方法名以及参数的类型和返回.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");
 }
}
Run Code Online (Sandbox Code Playgroud)

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

public class C {
 int y = 5;
 int z() {
   return 10;
 }
 int method1(int x) {
   return x + y + z();
 }
 ...
}
Run Code Online (Sandbox Code Playgroud)

下次运行时使用此类时,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;
 }
 ...
}
Run Code Online (Sandbox Code Playgroud)

Runtime.redirect调用将始终路由到类C的最新版本,因此调用new C().method1(10)将在代码更改之前返回15,之后返回25.这种实现错过了很多细节和优化,但你明白了.

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