出于调试目的和好奇心,我想列出加载到特定类加载器的所有类。
由于大多数类加载器的方法都是受保护的,因此,实现我想要的功能的最佳方法是什么?
谢谢!
出于调试目的和好奇心,我想列出加载到特定类加载器的所有类。
由于大多数类加载器的方法都是受保护的,因此,实现我想要的功能的最佳方法是什么?
谢谢!
试试这个。这是一种黑客式的解决方案,但它会起作用。
在任何类加载器(自1.0以来,在Sun的实现下)中,classes
字段保存了对由加载器定义的类的强引用,因此它们不会被垃圾回收。您可以通过反射获益。
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Vector<Class> classes = (Vector<Class>) f.get(classLoader);
Instrumentation.getInitiatedClasses(ClassLoader)
可以实现你想要的功能。
根据文档:
返回一个由加载器作为起始加载器的所有类组成的数组。
我不确定“起始加载器”是什么意思,如果这不能给出正确结果,请尝试使用 getAllLoadedClasses()
方法,并手动按 ClassLoader 进行过滤。
如何获取 Instrumentation
实例
只有代理 JAR(与应用程序 JAR 分离)才能获得 Instrumentation
接口的实例。一种简单的方法是创建一个代理 JAR,其中包含一个带有 premain
方法的类,该方法仅在系统属性中保存对 Instrumentation
实例的引用。
代理类示例:
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
-javaagent
选项)在命令行上指定。它可能会在不同的 ClassLoader
中加载两次,但这不是问题,因为系统 Properties
是每个进程单例。public class Main {
public static void main(String[] args) {
Instrumentation inst = InstrumentHook.getInstrumentation();
for (Class<?> clazz: inst.getAllLoadedClasses()) {
System.err.println(clazz.getName());
}
}
}
Class.forName
(即通过本地代码进行加载),但不适用于直接调用 ClassLoader.loadClass
。ClassLoader.findLoadedClass
的作用是检查在记录中是否有给定名称的类已经被启动类加载器初始化。 - bestsss