Рубрики
Без рубрики

Список всех классов, загруженных в определенный загрузчик классов

Список всех классов, загруженных определенным загрузчиком классов в Java

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы проанализируем метод , чтобы перечислить все классы, загруженные определенным загрузчиком классов в Java, используя Java Instrumentation API . Мы также увидим, как создать и загрузить агент Java, чтобы получить экземпляр Instrumentation и вызвать необходимые методы для выполнения нашей задачи.

2. Загрузчики классов в Java

Загрузчики классов являются неотъемлемой частью JRE (среды выполнения Java). Их задача состоит в том, чтобы динамически загружать классы в виртуальную машину Java . Другими словами, они загружают классы в память по требованию, когда это требуется приложением. В статье о загрузчиках классов Java рассказывается об их различных типах и дается подробное понимание того, как они работают.

3. Использование API инструментария

Интерфейс Instrumentation предоставляет метод get Initiated Classes(загрузчик загрузчика классов) , который может быть вызван для | возврата массива, содержащего все классы, загруженные конкретным загрузчиком . Давайте посмотрим, как это работает.

Во-первых, нам нужно создать и загрузить агент, чтобы получить экземпляр интерфейса Instrumentation . Агент Java – это инструмент для управления программами, запущенными на виртуальной машине Java (JVM).

Другими словами, он может добавлять или изменять байт-код методов с целью сбора данных. Нам потребуется агент , чтобы получить дескриптор экземпляра Instrumentation и вызвать необходимый метод.

Существует несколько способов создания и загрузки агента . В этом уроке мы будем использовать подход статической загрузки с использованием метода pre main и опции -javaagent .

3.1. Создание агента Java

Чтобы создать агент Java, нам нужно определить метод premain , которому будет передан экземпляр Instrumentation при загрузке агента . Теперь давайте создадим Список загруженных классов Агента класса:

public class ListLoadedClassesAgent {

    private static Instrumentation instrumentation;

    public static void premain(String agentArgs, Instrumentation instrumentation) {
        ListLoadedClassesAgent.instrumentation = instrumentation;
    }
}

3.2. Определение списка методов загружаемых классов

В дополнение к определению агента мы определим и представим статический метод для возврата массива загруженных классов для данного загрузчика классов.

Обратите внимание, что если мы передаем загрузчик классов со значением null в метод get Initiated Classes , он возвращает классы, загруженные загрузчиком классов начальной загрузки .

Давайте посмотрим на код в действии:

public static Class[] listLoadedClasses(String classLoaderType) {
    return instrumentation.getInitiatedClasses(
      getClassLoader(classLoaderType));
}

private static ClassLoader getClassLoader(String classLoaderType) {
    ClassLoader classLoader = null;
    switch (classLoaderType) {
        case "SYSTEM":
            classLoader = ClassLoader.getSystemClassLoader();
            break;
        case "EXTENSION":
            classLoader = ClassLoader.getSystemClassLoader().getParent();
            break;
        case "BOOTSTRAP":
            break;
        default:
            break;
    }
    return classLoader;
}

Обратите внимание, что если мы используем Java 9 или выше, мы можем использовать метод get PlatformClassLoader . Это будет список классов, загруженных загрузчиком классов платформы. В этом случае корпус переключателя также будет содержать:

case "PLATFORM":
    classLoader = ClassLoader.getPlatformClassLoader();
    break;

3.3. Создание файла Манифеста Агента

Теперь давайте создадим файл манифеста MANIFEST.MF с соответствующими атрибутами для запуска нашего агента, включая:

Premain-Class: com.baeldung.loadedclasslisting.ListLoadedClassesAgent

Полный список атрибутов манифеста для файла JAR агента доступен в официальной документации пакета java.lang.instrument .

3.4. Загрузка Агента и запуск приложения

Теперь давайте загрузим агент и запустим приложение. Во-первых, нам нужен файл JAR агента с файлом манифеста, содержащим информацию Premain-Class . Кроме того, нам нужен файл JAR приложения с файлом манифеста, содержащим информацию Main-Class . Класс Launcher , содержащий метод main , запустит наше приложение. Затем мы сможем распечатать классы, загруженные различными типами загрузчиков классов:

public class Launcher {

    public static void main(String[] args) {
        printClassesLoadedBy("BOOTSTRAP");
        printClassesLoadedBy("SYSTEM");
        printClassesLoadedBy("EXTENSION");
    }

    private static void printClassesLoadedBy(String classLoaderType) {
        System.out.println(classLoaderType + " ClassLoader : ");
        Class[] classes = ListLoadedClassesAgent.listLoadedClasses(classLoaderType);
        Arrays.asList(classes)
            .forEach(clazz -> System.out.println(clazz.getCanonicalName()));
    }
}

Далее, давайте статически загрузим агент Java и запустим наше приложение:

java -javaagent:agent.jar -jar app.jar

После выполнения приведенной выше команды мы увидим результат:

BOOTSTRAP ClassLoader :
java.lang.ClassValue.Entry[]
java.util.concurrent.ConcurrentHashMap.Segment
java.util.concurrent.ConcurrentHashMap.Segment[]
java.util.StringTokenizer
..............
SYSTEM ClassLoader : 
java.lang.Object[]
java.lang.Object[][]
java.lang.Class
java.lang.Class[]
..............
EXTENSION ClassLoader :
byte[]
char[]
int[]
int[][]
short[]

4. Заключение

В этом уроке мы узнали о методе перечисления всех классов, загруженных в определенный загрузчик классов.

Во-первых, мы создали агент Java. После этого мы определили метод для перечисления загруженных классов с помощью Java Instrumentation API. Наконец, мы создали файлы манифеста агента, загрузили агент и запустили наше приложение.

Как всегда, полный исходный код примера можно найти на GitHub .