手写一个javaagent
javaagent 可以在 main 方法执行前执行一些操作,比如增加一些特殊启动逻辑、在类完成加载前对类的字节码进行修改等。本文不谈底层原理,只介绍如何从零手写一个javaagent。
手写 javaagent
如下是一段简单的 HelloWorld
测试代码,其功能一目了然。
1 | public class HelloWorld { |
接下来要实现一个 javaagent,要在 HelloWorld
的 main
方法前执行,输出一些提示信息和参数。
编写 javaagent 代码
通过指定 javaagent 参数启动 java 虚拟机,在 main 方法执行前虚拟机会自动执行 public static void premain(String args, Instrumentation inst)
方法。下面的 AgentDemo
中实现了该方法,主要输出了参数信息。
1 | package com.gorden5566.demos.agent; |
编译代码
1 | javac AgentDemo.java -d . |
生成结果
1 | com |
编写 MANIFEST.MF
java 虚拟机通过 MANIFEST.MF
清单文件中的 Premain-Class
确定要执行哪个的类 premain
方法。手写一个 MANIFEST.MF
文件,输入如下内容:
1 | Premain-Class: com.gorden5566.demos.agent.AgentDemo |
打包 jar 文件
使用 jar
打包命令,指定打包后的 jar 文件名为 AgentDemo.jar
,清单文件为 MANIFEST.MF
,要打包的文件位于 com
目录下。
1 | jar cvfm AgentDemo.jar MANIFEST.MF -C com . |
输出信息如下:
1 | 已添加清单 |
使用 vim
打开 AgentDemo.jar
,查看文件内容
1 | " zip.vim version v28 |
选择 MANIFEST.MF
并查看,已经将 Premain-Class
项打包进去。
1 | Manifest-Version: 1.0 |
执行测试代码
编译 HelloWorld.java
1 | javac HelloWorld.java |
指定 javaagent 为 AgentDemo.jar
参数为 MyTest
,执行 HelloWorld
1 | java -javaagent:AgentDemo.jar=MyTest HelloWorld |
输出结果为:
1 | premain start! |
在 HelloWorld
的 main
方法执行前,先执行了 AgentDemo
的 premain
方法,输出了指定的参数信息。
- 2019-11-20
javaagent 使用 jar 文件格式进行打包,通过 jar 文件里的 manifest 清单文件指定被加载的类,用于启动 agent。
- 2019-09-28
本文通过编写一个简单的 HelloWorld 带你熟悉下 JNI,包括如何编写一个 JNI 方法,如何打包成动态链接库,如何加载并调用等。