Подтвердить что ты не робот

Как работает JRebel?

Использует ли JRebel Javassist или какую-то манипуляцию байт-кодами? Я прошу об этом из чистого интереса, мне не нужно "знать":)

4b9b3361

Ответ 1

JRebel использует переопределение классов (как ASM, так и Javassist) и JVM для версии отдельных классов. Кроме того, он интегрируется с серверами приложений, чтобы перенаправлять запросы класса/ресурса и веб-сервера обратно в рабочее пространство. И он также интегрируется с большинством серверов приложений и фреймворков для распространения изменений конфигурации (метаданных или файлов). Это не так. Долгое время требуется 10 инженеров мирового класса для разработки и поддержки и является нашей коммерческой тайной:)

Ответ 3

Это ближайшая аргументация, которую я прочитал о том, как работает 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);
 }
}

Когда Class 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.redirect всегда будет перенаправлен на последнюю версию класса C, поэтому вызов нового метода C(). method1 (10) вернет 15 до изменения кода и 25 после этого. Эта реализация пропускает много деталей и оптимизаций, но вы получаете эту идею.

Источник: http://zeroturnaround.com/rebellabs/why-hotswap-wasnt-good-enough-in-2001-and-still-isnt-today/