JRebel 是如何工作的?

发布于 2024-10-14 14:47:02 字数 63 浏览 6 评论 0原文

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

Does JRebel use Javassist or some kind of bytecode manipulation? I'm asking this out of pure interest, I don't actually "need" to know :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

(り薆情海 2024-10-21 14:47:02

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

JRebel uses class rewriting (both ASM and Javassist) and JVM integration to version individual classes. Plus it integrates with app servers to redirect class/resource and web server lookups back to the workspace. And it also integrates with most app servers and frameworks to propagate changes to the configuration (metadata or files). That's the short of it. The long of it takes 10 world-class engineers to develop and support and is our commercial secret :)

ㄖ落Θ余辉 2024-10-21 14:47:02

这是我读过的关于 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/

This is the closest reasoning I have read on how JRebel works by Simon, ZT Technical Evangelist.

Pasting the contents here:


Jrebel instruments the application and JVM classes to create a layer of indirection. In the case an application class is loaded, all method bodies will have a redirection using the runtime redirection service, as shown in Figure 2. This service manages and loads the class and method versions using anonymous inner classes created for each version that is reloaded. Let’s look at an example. We’ll create a new class C with two methods:

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

When Class C is loaded for the first time, JRebel instruments the class. The signature of this class will be the same, but the method bodies are now being redirected. The loaded class will now look something like this:

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

To the redirect calls, we passing in the calling object, the parameters to the method that has been called, our class name, our method name and the types of the parameters and return. JRebel also loads a class with the implementations at a specific version, initially version 0. Let’s see what that looks like:

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

Let’s now say the user changes their class C by adding a new method z() and invoking it from method1. Class C now looks like this:

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

The next time the runtimes uses this class, JRebel detects there is a newer version that has been compiled and on the filesystem, so it loads the new version, C1. This version has the additional method z and the updated implementation for method1.

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;
 }
 ...
}

The Runtime.redirect call will always be routed to the latest version of the class C, so calling new C().method1(10) would return 15 before the code change and 25 afterwards. This implementation misses a lot of detail and optimizations, but you get the idea.

Source: http://zeroturnaround.com/rebellabs/why-hotswap-wasnt-good-enough-in-2001-and-still-isnt-today/

音栖息无 2024-10-21 14:47:02

戴夫·布斯(Dave Booth)关于这个主题的精彩文章。 重新加载 Java 类: HotSwap 和 JRebel — 幕后花絮

Great article on this topic by Dave Booth. Reloading Java Classes: HotSwap and JRebel — Behind the Scenes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文