javaagent 规范

javaagent 使用 jar 文件格式进行打包,通过 jar 文件里的 manifest 清单文件指定被加载的类,用于启动 agent。

命令行接口

要通过命令行接口启动一个 javaagent,需要在启动命令中添加如下选项:

1
-javaagent:jarpath[=options]

其中 jarpath 是 javaagent 文件的路径,options 是 javaagent 的参数。这些配置可以在命令行中出现多次,这样就可以创建多个 agent。多个 agent 可以使用相同的 jarpath。agent jar 文件必须符合 jar 文件规范。

javaagent jar 文件的 manifest 清单中必须包含 Premain-Class 属性,该属性的值是 agent 类的名字。agent 类必须实现一个 public static premain 方法作为 agent 的入口。JVM 在初始化后,会按照 agent 的声明顺序依次调用对应的 premain 方法,然后再调用程序的 main 方法。

premain 方法有两种类型的签名,JVM 会先尝试调用如下签名的方法:

1
public static void premain(String agentArgs, Instrumentation inst);

如果 agent 类没有实现上面的方法,JVM 会接着尝试调用如下方法:

1
public static void premain(String agentArgs);

agent 类还可以实现 agentmain 方法,用于在 JVM 启动后开启 agent。当 agent 通过命令行方式启动时,agentmain 方法不会执行。

agent 类由系统类加载器进行加载,这也是 main 方法所属类的加载器,premain 方法会和 main 方法运行在同样的安全机制和类加载规则下。任何 main 方法可以做的事,对于 premain 来说都是合法的,包括创建线程。

javaagent 通过 agentArgs 参数传递 agent 选项,该参数作为 String 类型传递,agent 自己负责解析参数内容。

如果 agent 无法正常解析(例如 agent 类无法被加载,或者 agent 类没有合适的 premain 方法),则 JVM 会直接退出。此外,如果 premain 方法抛出了一个未捕获的异常,JVM 也会退出。

在 JVM 启动后启动 agent

还有一种机制,在 JVM 启动后的某个时机启动 javaagent。具体如何初始化的细节和具体的实现有关,通常情况下应用程序已经启动,JVM 已经调用过 main 方法。要支持这种方式,需要满足以下条件:

  1. Jar 文件的 manifest 清单中需包含 Agent-Class 属性,该属性的值为 agent 类的名字。
  2. agent 类必须实现一个 public static agentmain 方法。
  3. 系统类加载需提供一种机制,用于将 agent jar 文件加载到系统类路径中。

在 JVM 启动并调用完应用程序的 main 方法后,它会尝试调用 agentmain 方法。JVM 首先会尝试调用 agent 类里如下签名的方法:

1
public static void agentmain(String agentArgs, Instrumentation inst);

如果未实现上面的方法,JVM 则会尝试调用如下方法:

1
public static void agentmain(String agentArgs);

agent 类同样可以实现 premain 方法,用于通过命令行启动。若 agent 在 JVM 启动后再执行,则不会调用 premain 方法。

同样 agentArgs 参数需要 agent 自己解析并处理。

agentmain 方法需要完成启动 agent 所必须的初始化工作,在启动完成后该方法会退出。如果 agent 无法启动,则 JVM 会直接退出。若 agentmain 方法抛出未捕获的异常,JVM 也会直接退出。

Manifest 属性

如下是 agent jar 文件支持的 manifest 属性:

  • Premain-Class

    通过命令行启动时,用于指定 agent 类,值为 agent 类的名字,该 agent 类中需包含 premain 方法

  • Agent-Class

    在 JVM 虚拟机启动后再启动 agent,用于指定 agent 类,值为 agent 类的名字,该 agent 类中需包含 agentmain 方法

  • Boot-Class-Path

    指定启动类加载器搜索的路径列表。

  • Can-Redefine-Classes

    可选参数,值为 true 或 false。默认值 false。agent 是否需要 redefine 类的能力。

  • Can-Retransform-Classes

    可选参数,值为 true 或 false。默认值 false。agent 是否需要 retransform 类的能力。

  • Can-Set-Native-Method-Prefix

    可选参数,值为 true 或 false。默认值 false。agent 是否需要设置 native 方法前缀的能力。