したがって、一連の「特別な」クラスをメモリ内に保持するクラスローダー (MyClassLoader) があります。これらの特別なクラスは動的にコンパイルされ、MyClassLoader 内のバイト配列に格納されます。MyClassLoader がクラスを要求されるspecialClasses
と、システム クラスローダーに委譲する前に、辞書にそのクラスが含まれているかどうかを最初にチェックします。次のようになります。
class MyClassLoader extends ClassLoader {
Map<String, byte[]> specialClasses;
public MyClassLoader(Map<String, byte[]> sb) {
this.specialClasses = sb;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (specialClasses.containsKey(name)) return findClass(name);
else return super.loadClass(name);
}
@Override
public Class findClass(String name) {
byte[] b = specialClasses.get(name);
return defineClass(name, b, 0, b.length);
}
}
で変換 (計測など) を実行したい場合は、呼び出す前にspecialClasses
を変更するだけで実行できます。byte[]
defineClass()
System クラスローダによって提供されるクラスも変換したいと思いますが、System クラスローダは、それが提供する生byte[]
のクラスにアクセスする方法を提供していないようで、Class
オブジェクトを直接提供します。
JVM にロードされたすべてのクラスを計測することもできますが、-javaagent
計測したくないクラスにオーバーヘッドが追加されます。MyClassLoader によってロードされたクラスのみを計測したいだけです。
byte[]
親クラスローダによって提供される生のクラスを取得する方法はありますか?そのため、独自のコピーを定義する前にインストルメント化できますか?byte[]
あるいは、 MyClassLoader がすべてのシステム クラス (オブジェクト、文字列など) の独自のコピーを計測および定義できるように、システム クラスローダーの機能をエミュレートする方法はありますか?
編集:
だから私は別のアプローチを試しました:
- を使用して、ロードされたすべてのクラスの を
-javaagent
キャプチャし、byte[]
クラスの名前をキーとしてハッシュテーブルに保存します。 - MyClassLoader は、システム クラスをその親クラスローダーに委譲する代わりに、クラス名を使用してこのハッシュテーブルからバイトコードをロードし、それを定義します。
理論的には、これにより、MyClassLoader がインストルメンテーションを使用して独自のバージョンのシステム クラスを定義できるようになります。ただし、それは失敗します
java.lang.SecurityException: Prohibited package name: java.lang
明らかに、JVM は私が自分でクラスを定義することを好みませんjava.lang
。たとえ (理論的には)byte[]
ブートストラップでロードされたクラスと同じソースから取得する必要があるとしてもです。解決策の探求は続きます。
EDIT2:
私はこの問題に対する (非常に大ざっぱな) 解決策を見つけましたが、Java のクラスローディング/インスツルメンテーションの複雑さについて私よりもよく知っている人が大ざっぱではないものを思い付くことができれば、それは素晴らしいことです。