Для причин отладки и любопытства я хочу перечислить все классы, загруженные в определенный загрузчик классов.
Увидев, что большинство методов загрузчика классов защищены, что лучший способ выполнить то, что я хочу?
Спасибо!
Для причин отладки и любопытства я хочу перечислить все классы, загруженные в определенный загрузчик классов.
Увидев, что большинство методов загрузчика классов защищены, что лучший способ выполнить то, что я хочу?
Спасибо!
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
В результате JAR должен ссылаться на приложение и указываться в командной строке (с опцией -javaagent
) при запуске приложения. Он может быть загружен дважды в разных ClassLoader
s, но это не проблема, так как система Properties
является одноточечным процессом.
Пример класса приложения
public class Main {
public static void main(String[] args) {
Instrumentation inst = InstrumentHook.getInstrumentation();
for (Class<?> clazz: inst.getAllLoadedClasses()) {
System.err.println(clazz.getName());
}
}
}
Попробуйте это. Это хакерское решение, но оно будет делать.
Поле classes
в любом загрузчике классов (под Sun impl с 1.0) содержит твердую ссылку на классы, определенные загрузчиком, поэтому они не будут GC'd. Вы можете извлечь выгоду из отражения.
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Vector<Class> classes = (Vector<Class>) f.get(classLoader);