Module  java.instrument

Package java.lang.instrument

提供允许Java编程语言代理仪器在JVM上运行程序的服务。 仪器的机制是修改方法的字节码。

代理部署为JAR文件。 JAR文件清单中的一个属性指定将加载以启动代理的代理类。 代理商可以通过几种方式启动:

  1. 对于支持命令行界面的实现,可以通过在命令行中指定选项来启动代理。

  2. 虚拟机启动后,实现可能会支持启动代理的机制。 例如,实现可以提供一种机制,其允许工具附加到正在运行的应用,并且启动将该工具的代理加载到正在运行的应用中。

  3. 代理可以与可执行JAR文件中的应用程序一起打包。

以下描述了启动代理的这些方法中的每一种。

从命令行界面启动代理

如果实现提供了从命令行界面启动代理的方法,则通过向命令行添加以下选项来启动代理:

-javaagent:<jarpath>[=<options>]
其中<jarpath>是代理JAR文件的路径,而<options>是代理选项。

代理JAR文件的清单必须在其主清单中包含属性Premain-Class 该属性的值是代理类的名称。 代理类必须实现一个类似于main应用程序入口点的公共静态方法premain方法。 Java虚拟机(JVM)初始化后,将调用premain方法,然后实际应用程序为main方法。 premain方法必须返回,以便启动继续。

premain方法具有两种可能的签名之一。 JVM首先尝试在代理类上调用以下方法:

public static void premain(String agentArgs, Instrumentation inst)

如果代理类不实现此方法,则JVM将尝试调用:

public static void premain(String agentArgs)

代理程序类也可能有一个agentmain方法,用于启动虚拟机启动后的代理(见下文)。 当使用命令行选项启动代理程序时,不会调用agentmain方法。

每个代理通过agentArgs参数传递其代理选项。 代理选项作为单个字符串传递,任何其他解析都应由代理本身执行。

如果代理无法启动(例如,因为代理类无法加载,或者代理类没有适当的premain方法),则JVM将中止。 如果一个premain方法抛出一个未捕获的异常,JVM将中止。

不需要实现提供从命令行界面启动代理的方法。 那么它支持-javaagent选项,如上所述。 -javaagent选项可能会在同一命令行上多次使用,从而启动多个代理。 将按照命令行中指定代理的顺序调用premain方法。 多个代理可以使用相同的<jarpath>

对于代理商premain方法可以做什么,没有建模限制。 任何应用程序main可以做,包括创建线程,从premain是合法的。

VM启动后启动代理

实现可以提供在VM启动之后的某个时间启动代理的机制。 关于如何启动的细节是具体实现的,但通常应用程序已经启动,并且已经调用了它的main方法。 在VM启动后,实现支持启动代理的情况适用于以下情况:

  1. 代理JAR的清单必须包含属性Agent-Class在其主manfiest。 该属性的值是代理类的名称。

  2. 代理类必须实现一个公共静态的agentmain方法。

agentmain方法具有两种可能的签名之一。 JVM首先尝试在代理类上调用以下方法:

public static void agentmain(String agentArgs, Instrumentation inst)

如果代理类不实现此方法,则JVM将尝试调用:

public static void agentmain(String agentArgs)

当使用命令行选项启动代理时,代理类也可能具有premain方法。 虚拟机启动后启动代理时,不会调用premain方法。

代理通过agentArgs参数传递其代理选项。 代理选项作为单个字符串传递,任何其他解析都应由代理本身执行。

agentmain方法应该执行启动代理所需的任何必需的初始化。 启动完成后,方法应该返回。 如果代理无法启动(例如,由于代理类不能加载,或者由于代理类不具有一致性agentmain方法),则JVM不会中止。 如果agentmain方法抛出未捕获的异常,则它将被忽略(但为了进行故障排除,可能会被JVM记录)。

在可执行的JAR文件中包含一个代理

JAR文件规范定义了作为可执行JAR文件打包的独立应用程序的清单属性。 如果实现支持将启动应用程序作为可执行JAR的机制,则主清单可能包括Launcher-Agent-Class属性,以指定在调用应用程序main方法之前启动的代理程序的类名。 Java虚拟机尝试在代理类上调用以下方法:

public static void agentmain(String agentArgs, Instrumentation inst)

如果代理类不实现此方法,则JVM将尝试调用:

public static void agentmain(String agentArgs)

agentArgs参数的值始终为空字符串。

agentmain方法应该执行启动代理并返回所需的任何必需的初始化。 如果代理无法启动,例如代理类不能加载,则代理类不定义一致的agentmain方法,或者agentmain方法抛出未捕获的异常或错误,JVM将中止。

加载代理类和可用于代理类的模块/类

从代理JAR文件加载的类由system class loader加载,并且是系统类加载器的成员unnamed module 系统类加载器通常定义包含应用程序main方法的类。

代理类可见的类是系统类加载器可见的类,最低限度包括:

  • 包中导出的包中的类在boot layer中 引导层是否包含所有平台模块将取决于初始模块或应用程序的启动方式。

  • 可以由系统类加载器(通常是类路径)定义为其未命名模块的成员的类。

  • 代理安排的任何类都由引导类加载器定义为其未命名模块的成员。

如果代理类需要链接到不在引导层的平台(或其他)模块中的类,则可能需要以确保这些模块位于引导层中的方式启动应用程序。 例如,在JDK实现中,可以使用--add-modules命令行选项将模块添加到启动时解析的根模块集。

代理安排由引导类加载器(通过appendToBootstrapClassLoaderSearch或下面指定的Boot-Class-Path属性)加载的支持类必须链接到定义到引导类加载器的类。 不能保证所有平台类都可以由引导类加载器定义。

如果自定义系统类加载器被配置(由系统属性的手段java.system.class.loader作为指定getSystemClassLoader方法),那么它必须定义appendToClassPathForInstrumentation如在指定的方法appendToSystemClassLoaderSearch 换句话说,自定义系统类加载器必须支持将代理JAR文件添加到系统类加载器搜索的机制。

清单属性

为代理JAR文件定义了以下清单属性:

Premain-Class
When an agent is specified at JVM launch time this attribute specifies the agent class. That is, the class containing the premain method. When an agent is specified at JVM launch time this attribute is required. If the attribute is not present the JVM will abort. Note: this is a class name, not a file name or path.
Agent-Class
If an implementation supports a mechanism to start agents sometime after the VM has started then this attribute specifies the agent class. That is, the class containing the agentmain method. This attribute is required if it is not present the agent will not be started. Note: this is a class name, not a file name or path.
Launcher-Agent-Class
If an implementation supports a mechanism to start an application as an executable JAR then the main manifest may include this attribute to specify the class name of an agent to start before the application main method is invoked.
Boot-Class-Path
A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms). These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed. Paths in the list are separated by one or more spaces. A path takes the syntax of the path component of a hierarchical URI. The path is absolute if it begins with a slash character ('/'), otherwise it is relative. A relative path is resolved against the absolute path of the agent JAR file. Malformed and non-existent paths are ignored. When an agent is started sometime after the VM has started then paths that do not represent a JAR file are ignored. This attribute is optional.
Can-Redefine-Classes
Boolean ( true or false, case irrelevant). Is the ability to redefine classes needed by this agent. Values other than true are considered false. This attribute is optional, the default is false.
Can-Retransform-Classes
Boolean ( true or false, case irrelevant). Is the ability to retransform classes needed by this agent. Values other than true are considered false. This attribute is optional, the default is false.
Can-Set-Native-Method-Prefix
Boolean ( true or false, case irrelevant). Is the ability to set native method prefix needed by this agent. Values other than true are considered false. This attribute is optional, the default is false.

代理JAR文件可能具有清单中存在的Premain-ClassAgent-Class属性。 当使用-javaagent选项在命令行启动代理时, Premain-Class属性指定代理类的名称,并忽略Agent-Class属性。 类似地,如果代理在VM启动后的某个时间启动,则Agent-Class属性指定代理类的名称(值为Premain-Class属性的值将被忽略)。

在模块中调用代码

作为在引导类加载器的搜索路径上部署支持类的代理或加载主代理类的类加载器的搜索路径的帮助,Java虚拟机安排转换类的模块读取未命名的模块的两个类装载机。

从以下版本开始:
1.5