Package java.lang.instrument
代理部署为JAR文件。 JAR文件清单中的一个属性指定将加载以启动代理的代理类。 代理商可以通过几种方式启动:
对于支持命令行界面的实现,可以通过在命令行中指定选项来启动代理。
虚拟机启动后,实现可能会支持启动代理的机制。 例如,实现可以提供一种机制,其允许工具附加到正在运行的应用,并且启动将该工具的代理加载到正在运行的应用中。
代理可以与可执行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启动后,实现支持启动代理的情况适用于以下情况:
代理JAR的清单必须包含属性
Agent-Class
在其主manfiest。 该属性的值是代理类的名称。代理类必须实现一个公共静态的
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
orfalse
, case irrelevant). Is the ability to redefine classes needed by this agent. Values other thantrue
are consideredfalse
. This attribute is optional, the default isfalse
.Can-Retransform-Classes
- Boolean (
true
orfalse
, case irrelevant). Is the ability to retransform classes needed by this agent. Values other thantrue
are consideredfalse
. This attribute is optional, the default isfalse
.Can-Set-Native-Method-Prefix
- Boolean (
true
orfalse
, case irrelevant). Is the ability to set native method prefix needed by this agent. Values other thantrue
are consideredfalse
. This attribute is optional, the default isfalse
.
代理JAR文件可能具有清单中存在的Premain-Class
和Agent-Class
属性。 当使用-javaagent
选项在命令行启动代理时, Premain-Class
属性指定代理类的名称,并忽略Agent-Class
属性。 类似地,如果代理在VM启动后的某个时间启动,则Agent-Class
属性指定代理类的名称(值为Premain-Class
属性的值将被忽略)。
在模块中调用代码
作为在引导类加载器的搜索路径上部署支持类的代理或加载主代理类的类加载器的搜索路径的帮助,Java虚拟机安排转换类的模块读取未命名的模块的两个类装载机。
- 从以下版本开始:
- 1.5
-
接口摘要 接口 描述 ClassFileTransformer 类文件的变压器。Instrumentation 该类提供了用于设计Java编程语言代码所需的服务。 -
类摘要 Class 描述 ClassDefinition 该类作为Instrumentation.redefineClasses
方法的参数块。 -
异常摘要 异常 描述 IllegalClassFormatException 当其输入参数无效时,通过执行ClassFileTransformer.transform
进行抛出。UnmodifiableClassException 当其中一个指定的类不能修改时,通过执行Instrumentation.redefineClasses
抛出。UnmodifiableModuleException Thrown to indicate that a module cannot be modified.