JRebel は Javassist またはある種のバイトコード操作を使用しますか? 私は純粋な興味からこれを求めています、私は実際に知る必要はありません:)
3 に答える
JRebelは、クラスの書き換え(ASMとJavassistの両方)とJVM統合を使用して、個々のクラスをバージョン管理します。さらに、アプリサーバーと統合して、クラス/リソースとウェブサーバーのルックアップをワークスペースにリダイレクトします。また、ほとんどのアプリサーバーおよびフレームワークと統合して、構成(メタデータまたはファイル)への変更を伝達します。それはそれの不足です。その長い間、開発とサポートには10人の世界クラスのエンジニアが必要であり、これが企業秘密です:)
Dave Booth によるこのトピックに関するすばらしい記事。Java クラスのリロード: HotSwap および JRebel — 舞台裏.
これは、JRebel がどのように動作するかについて、ZT テクニカル エバンジェリストの Simon によって私が読んだ最も近い推論です。
ここにコンテンツを貼り付けます:
Jrebel は、アプリケーションと JVM クラスを計測して、間接化のレイヤーを作成します。アプリケーション クラスが読み込まれる場合、図 2 に示すように、すべてのメソッド本体はランタイム リダイレクト サービスを使用してリダイレクトされます。例を見てみましょう。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");
}
}
ここで、ユーザーがクラス C を変更して、新しいメソッド z() を追加し、それを method1 から呼び出すとします。クラス C は次のようになります。
public class C {
int y = 5;
int z() {
return 10;
}
int method1(int x) {
return x + y + z();
}
...
}
次にランタイムがこのクラスを使用するとき、JRebel は、コンパイル済みでファイルシステム上に新しいバージョンがあることを検出するため、新しいバージョン C1 をロードします。このバージョンには、メソッド z が追加され、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;
}
...
}
Runtime.redirect 呼び出しは常にクラス C の最新バージョンにルーティングされるため、 new C().method1(10) を呼び出すと、コード変更前に 15 が返され、変更後に 25 が返されます。この実装には多くの詳細と最適化が欠けていますが、アイデアは理解できます。
ソース: http://zeroturnaround.com/rebellabs/why-hotswap-wasnt-good-enough-in-2001-and-still-isnt-today/