|
编写 premain 函数
编写一个 Java 类,包含如下两个方法当中的任何一个
public static void premain(String agentArgs, Instrumentation inst); [1] public static void premain(String agentArgs); [2]
其中,[1] 的优先级比 [2] 高,将会被优先执行([1] 和 [2] 同时存在时,[2] 被忽略)。
在这个 premain 函数中,开发者可以进行对类的各种操作。
agentArgs 是 premain 函数得到的程序参数,随同 “–javaagent”一起传入。与 main 函数不同的是,这个参数是一个字符串而不是一个字符串数组,假如程序参数有多个,程序将自行解析这个字符串。
Inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入。java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口,也是这个包的核心部分,集中了其中几乎所有的功能方法,例如类定义的转换和操作等等。
jar 文件打包
将这个 Java 类打包成一个 jar 文件,并在其中的 manifest 属性当中加入” Premain-Class”来指定步骤 1 当中编写的那个带有 premain 的 Java类。(可能还需要指定其他属性以开启更多功能)
运行
用如下方式运行带有 Instrumentation 的 Java 程序:
java -javaagent:jar文件的位置[=传入premain的参数]
对 Java 类文件的操作,可以理解为对一个 byte 数组的操作(将类文件的二进制字节流读入一个 byte 数组)。开发者可以在“ClassFileTransformer”的 transform 方法当中得到,操作并最终返回一个类的定义(一个 byte 数组)。这方面,Apache 的 BCEL 开源项目提供了强有力的支持,读者可以在参考文章“Java SE 5 特性 Instrumentation 实践”中看到一个 BCEL 和 Instrumentation 结合的例子。具体的字节码操作并非本文的重点,所以,本文中所举的例子,只是采用简单的类文件替换的方式来演示 Instrumentation 的使用。
下面,我们通过简单的举例,来说明 Instrumentation 的基本使用方法。
首先,我们有一个简单的类,TransClass, 可以通过一个静态方法返回一个整数 1。
public class TransClass { public int getNumber() { return 1; } } 我们运行如下类,可以得到输出 ”1“。
public class TestMainInJar { public static void main(String[] args) { System.out.println(new TransClass().getNumber()); } } 然后,我们将 TransClass 的 getNumber 方法改成如下:
public int getNumber() { return 2; } 再将这个返回 2 的 Java 文件编译成类文件,为了区别开原有的返回 1 的类,我们将返回 2 的这个类文件命名为 TransClass2.class.2。
接下来,我们建立一个 Transformer 类:
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.Pro???椠?? tectionDomain;
class Transformer implements ClassFileTransformer { public static final String classNumberReturns2 = "TransClass.class.2";
|
| 共3页: 上一页 [1] 2 [3] 下一页 |
评论加载中…