Пакет java.lang.instrument

Предоставляет службы, которые позволяют агентам языка программирования Java инструментировать программы, выполняющиеся в JVM. Механизм инструментирования — модификация байткода методов.

Примечание: разработчики/администраторы несут ответственность за проверку надежности содержимого и структуры Java-агентов, которые они развертывают, так как эти агенты могут произвольно преобразовывать байткод из других JAR-файлов. Поскольку это происходит после того, как JAR-файлы с байткодом были проверены на достоверность, достоверность Java-агента может определить доверие ко всему приложению.

Агент развертывается в виде JAR-файла. Атрибут в манифесте JAR-файла указывает класс агента, который будет загружен для запуска агента. Агенты могут запускаться несколькими способами:

  1. Для реализаций, поддерживающих интерфейс командной строки, агент может быть запущен путем указания параметра в командной строке.

  2. Реализация может поддерживать механизм запуска агентов некоторое время после запуска VM. Например, реализация может предоставить механизм, который позволяет инструменту присоединиться к работающему приложению и инициировать загрузку агента инструмента в работающее приложение.

  3. Агент может быть упакован с приложением в исполняемый JAR-файл.

Каждый из этих способов запуска агента описан ниже.

Запуск агента из интерфейса командной строки

Там, где реализация предоставляет способ запуска агентов из интерфейса командной строки, агент запускается путем добавления следующего параметра в командную строку:

-javaagent:<jarpath>[=<options>]
где <jarpath> — путь к JAR-файлу агента, а <options> — параметры агента.

Манифест JAR-файла агента должен содержать атрибут Premain-Class в своем главном манифесте. Значение этого атрибута — имя класса агента. Класс агента должен реализовывать общедоступный статический premain метод, аналогичный по принципу main точке входа приложения. После того, как Java Virtual Machine (JVM) была инициализирована, будет вызван метод premain, а затем метод реального приложения main. Метод premain должен завершиться, чтобы запуск продолжился.

Метод premain имеет одну из двух возможных сигнатур. JVM сначала пытается вызвать следующий метод в классе агента:

public static void premain(String agentArgs, Instrumentation inst)

Если класс агента не реализует этот метод, JVM попытается вызвать:

public static void premain(String agentArgs)

Класс агента может также иметь метод agentmain для использования при запуске агента после запуска VM (см. ниже). Когда агент запускается с помощью параметра командной строки, метод agentmain не вызывается.

Каждый агент получает свои параметры агента через параметр agentArgs. Параметры агента передаются как строка, любое дополнительное разбиение должно выполняться самим агентом.

Если агент не может быть запущен (например, потому что класс агента не может быть загружен или потому что класс агента не имеет соответствующего метода premain), JVM прервется. Если метод premain вызывает неперехваченное исключение, JVM прервется.

Реализация не обязана предоставлять способ запуска агентов из интерфейса командной строки. Когда она это делает, она поддерживает параметр -javaagent, как указано выше. Параметр -javaagent может использоваться несколько раз в одной командной строке, тем самым запуская несколько агентов. Методы premain будут вызываться в том порядке, в котором агенты указаны в командной строке. Более одного агента могут использовать тот же <jarpath>.

Нет ограничений на то, что может делать метод агента premain. Всё, что может делать приложение main, включая создание потоков, законно с точки зрения premain.

Запуск агента после запуска VM

Реализация может предоставить механизм запуска агентов в какой-то момент после запуска VM. Подробности о том, как это инициируется, зависят от реализации, но, как правило, приложение уже запущено, и его метод main уже вызван. В случаях, когда реализация поддерживает запуск агентов после запуска VM, применяется следующее:

  1. Манифест JAR-файла агента должен содержать атрибут Agent-Class в своем главном манифесте. Значение этого атрибута — имя класса агента.

  2. Класс агента должен реализовывать общедоступный статический метод agentmain.

Метод agentmain имеет одну из двух возможных сигнатур. JVM сначала пытается вызвать следующий метод в классе агента:

public static void agentmain(String agentArgs, Instrumentation inst)

Если класс агента не реализует этот метод, JVM попытается вызвать:

public static void agentmain(String agentArgs)

Класс агента может также иметь метод premain для использования при запуске агента с помощью параметра командной строки. При запуске агента после запуска VM метод premain не вызывается.

Агент получает свои параметры агента через параметр agentArgs. Параметры агента передаются как строка, любое дополнительное разбиение должно выполняться самим агентом.

Метод agentmain должен выполнять необходимую инициализацию для запуска агента. После завершения запуска метод должен возвратиться. Если агент не может быть запущен (например, потому что класс агента не может быть загружен или потому что класс агента не имеет соответствующего метода agentmain), JVM не прервется. Если метод agentmain вызывает неперехваченное исключение, оно будет проигнорировано (но может быть записано JVM для отладки).

Включение агента в исполняемый JAR-файл

Спецификация JAR-файлов определяет атрибуты манифеста для автономных приложений, упакованных в виде исполняемых JAR-файлов. Если реализация поддерживает механизм запуска приложения как исполняемого JAR-файла, то в главном манифесте можно включить атрибут Launcher-Agent-Class для указания имени класса агента, который нужно запустить перед вызовом метода приложения main. JVM пытается вызвать следующий метод в классе агента:

public static void agentmain(String agentArgs, Instrumentation inst)

Если класс агента не реализует этот метод, JVM попытается вызвать:

public static void agentmain(String agentArgs)

Значение параметра agentArgs всегда является пустой строкой.

Метод agentmain должен выполнить необходимую инициализацию для запуска агента и вернуть значение. Если агент не может быть запущен, например, класс агента не может быть загружен, класс агента не определяет соответствующий метод agentmain, или метод agentmain вызывает неперехваченное исключение или ошибку, JVM прервется.

Загрузка классов агентов и модулей/классов, доступных классу агента

Классы, загруженные из JAR-файла агента, загружаются системным загрузчиком классов и являются членами безымянного модуля системного загрузчика классов. Системный загрузчик классов обычно определяет и класс, содержащий метод приложения main.

Классы, видимые для класса агента, — это классы, видимые для системного загрузчика классов, и, как минимум, включают:

  • Классы в пакетах, экспортированных модулями в слое загрузки платформы (слой загрузки). Содержит ли слой загрузки все платформенные модули или нет, зависит от начального модуля или того, как было запущено приложение.

  • Классы, которые могут быть определены системным загрузчиком классов (обычно в пути к классам) как члены его безымянного модуля.

  • Любые классы, которые агент организует для определения загрузчиком классов платформы как члены его безымянного модуля.

Если классы агентов должны связываться с классами в платформенных (или других) модулях, которые не находятся в слое загрузки, то приложение может потребоваться запустить таким образом, чтобы эти модули находились в слое загрузки. В реализации JDK, например, параметр командной строки --add-modules может быть использован для добавления модулей в набор корневых модулей для разрешения при запуске.

Поддерживающие классы, которые агент организует для загрузки загрузчиком классов платформы (с помощью appendToBootstrapClassLoaderSearch или атрибута Boot-Class-Path ниже), должны связываться только с классами, определенными для загрузчика классов платформы. Нет гарантии, что все платформенные классы могут быть определены загрузчиком классов платформы.

Если настроен пользовательский системный загрузчик классов (с помощью системной переменной java.system.class.loader как указано в методе getSystemClassLoader), то он должен определить метод appendToClassPathForInstrumentation как указано в appendToSystemClassLoaderSearch. Другими словами, пользовательский системный загрузчик классов должен поддерживать механизм добавления JAR-файла агента в поиск системного загрузчика классов.

Атрибуты манифеста

Для JAR-файла агента определены следующие атрибуты манифеста:

Premain-Class
При указании агента во время запуска JVM, этот атрибут задаёт класс агента. То есть, класс, содержащий метод premain. При указании агента во время запуска JVM этот атрибут обязателен. Если атрибут отсутствует, JVM прервётся. Примечание: это имя класса, а не имя файла или путь.
Agent-Class
Если реализация поддерживает механизм запуска агентов некоторое время после запуска виртуальной машины, этот атрибут задаёт класс агента. То есть, класс, содержащий метод agentmain. Этот атрибут обязателен; если он отсутствует, агент не будет запущен. Примечание: это имя класса, а не имя файла или путь.
Launcher-Agent-Class
Если реализация поддерживает механизм запуска приложения как исполняемого JAR-файла, то основной манифест может содержать этот атрибут для указания имени класса агента, который должен быть запущен до вызова метода приложения main.
Boot-Class-Path
Список путей, которые будет искать загрузчик базовых классов. Пути представляют собой каталоги или библиотеки (часто называемые JAR- или ZIP-библиотеками во многих платформах). Эти пути ищутся загрузчиком базовых классов после того, как платформа не смогла найти класс стандартным способом. Пути просматриваются в указанном порядке. Пути в списке разделяются одним или несколькими пробелами. Путь имеет синтаксис компонента пути иерархического URI. Путь является абсолютным, если он начинается с символа косой черты ('/'), в противном случае он является относительным. Относительный путь разрешается относительно абсолютного пути к файлу JAR агента. Неправильные и несуществующие пути игнорируются. При запуске агента некоторое время после запуска виртуальной машины, пути, не представляющие собой JAR-файл, игнорируются. Этот атрибут является необязательным.
Can-Redefine-Classes
Булево значение (true или false, регистр не важен). Необходима ли возможность переопределения классов для этого агента. Значения, отличные от true, рассматриваются как false. Этот атрибут является необязательным, по умолчанию значение false.
Can-Retransform-Classes
Булево значение (true или false, регистр не важен). Необходима ли возможность повторной трансформации классов для этого агента. Значения, отличные от true, рассматриваются как false. Этот атрибут является необязательным, по умолчанию значение false.
Can-Set-Native-Method-Prefix
Булево значение (true или false, регистр не важен). Необходима ли возможность установки префикса для методов нативных вызовов для этого агента. Значения, отличные от true, рассматриваются как false. Этот атрибут является необязательным, по умолчанию значение false.

Файл JAR агента может содержать как атрибут Premain-Class, так и атрибут Agent-Class в манифесте. При запуске агента из командной строки с использованием параметра -javaagent, атрибут Premain-Class указывает имя класса агента, а атрибут Agent-Class игнорируется. Аналогично, если агент запускается некоторое время после запуска виртуальной машины, атрибут Agent-Class указывает имя класса агента (значение атрибута Premain-Class игнорируется).

Инструментирование кода в модулях

Для помощи агентам, которые развертывают вспомогательные классы в пути поиска загрузчика базовых классов или в пути поиска загрузчика, загружающего главный класс агента, виртуальная машина Java организует чтение модуля преобразованных классов в безымянный модуль обоих загрузчиков.

Since:
1.5
Интерфейс Описание
ClassFileTransformer

Трансформатор файлов классов.

Instrumentation

Этот класс предоставляет службы, необходимые для инструментирования кода языка программирования Java.

Класс Описание
ClassDefinition

Этот класс служит блоком параметров для метода Instrumentation.redefineClasses.

Исключение Описание
IllegalClassFormatException

Выбрасывается реализацией ClassFileTransformer.transform при некорректных входных параметрах.

UnmodifiableClassException

Выбрасывается реализацией Instrumentation.redefineClasses, когда один из указанных классов не может быть изменён.

UnmodifiableModuleException

Выбрасывается для указания того, что модуль не может быть изменён.

© 1993, 2020, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/11/docs/api/java.instrument/java/lang/instrument/package-summary.html

Spec-Zone .ru
спецификации, руководства, описания, API