デバッグ上の理由と好奇心から、特定のクラスローダーにロードされたすべてのクラスを一覧表示したいと思います。
クラスローダーのほとんどのメソッドが保護されているのを見て、私が望むことを達成する最良の方法は何ですか?
ありがとう!
Instrumentation.getInitiatedClasses(ClassLoader)
はあなたが望むことをするかもしれません。
ドキュメントによると:
ローダーが開始ローダーであるすべてのクラスの配列を返します。
しかし、「ローダーを開始する」の意味がわかりません。正しい結果が得られない場合は、getAllLoadedClasses()
メソッドを使用し、ClassLoaderで手動でフィルタリングしてみてください。
Instrumentation
のインスタンスを取得する方法
Instrumentation
インターフェイスのインスタンスを取得できるのは、エージェントJAR(アプリケーションJARとは別)のみです。アプリケーションで使用できるようにする簡単な方法は、システムプロパティにpremain
インスタンスへの参照を保存するだけのInstrumentation
メソッドを持つ1つのクラスを含むエージェントJARを作成することです。
エージェントクラスの例:
public class InstrumentHook {
public static void premain(String agentArgs, Instrumentation inst) {
if (agentArgs != null) {
System.getProperties().put(AGENT_ARGS_KEY, agentArgs);
}
System.getProperties().put(INSTRUMENTATION_KEY, inst);
}
public static Instrumentation getInstrumentation() {
return (Instrumentation) System.getProperties().get(INSTRUMENTATION_KEY);
}
// Needn't be a UUID - can be a String or any other object that
// implements equals().
private static final Object AGENT_ARGS_KEY =
UUID.fromString("887b43f3-c742-4b87-978d-70d2db74e40e");
private static final Object INSTRUMENTATION_KEY =
UUID.fromString("214ac54a-60a5-417e-b3b8-772e80a16667");
}
マニフェストの例:
Manifest-Version: 1.0
Premain-Class: InstrumentHook
生成されたJARは、コマンドラインで指定されたアプリケーションおよび(-javaagent
オプション)アプリケーションを起動するとき。異なるClassLoader
sに2回ロードされる場合がありますが、システムProperties
はプロセスごとのシングルトンであるため、問題はありません。
サンプルアプリケーションクラス
public class Main {
public static void main(String[] args) {
Instrumentation inst = InstrumentHook.getInstrumentation();
for (Class<?> clazz: inst.getAllLoadedClasses()) {
System.err.println(clazz.getName());
}
}
}
これを試して。それはハッカー的な解決策ですが、それはします。
クラスローダ(1.0以降のSunの実装下)のclasses
フィールドは、ローダによって定義されたクラスへのハード参照を保持するため、GCされません。リフレクションを介して恩恵を受けることができます。
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Vector<Class> classes = (Vector<Class>) f.get(classLoader);