java instrument学习总结

Instrumentation介绍:

Java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。JavaSE5中使用JVM TI替代了JVM PI和JVM DI。提供一套代理机制,支持独立于JVM应用程序之外的程序以代理的方式连接和访问JVM。Instrumentation 的最大作用就是类定义的动态改变和操作。在Java SE5 及其后续版本当中,开发者可以在一个普通Java程序(带有 main 函数的 Java 类)运行时,通过 – javaagent 参数指定一个特定的 jar 文件(包含 Instrumentation 代理)来启动 Instrumentation 的代理程序。

premain方式

在Java SE5时代,Instrument只提供了premain一种方式,即在真正的应用程序(包含main方法的程序)main方法启动前启动一个代理程序。例如使用如下命令:

[java]view plaincopy

java -javaagent:agent_jar_path[=options] java_app_name

[java]view plaincopy

java -javaagent:agent_jar_path[=options] java_app_name

可以在启动名为java_app_name的应用之前启动一个agent_jar_path指定位置的agent jar。 实现这样一个agent jar包,必须满足两个条件:

在这个jar包的manifest文件中包含Premain-Class属性,并且改属性的值为代理类全路径名。

代理类必须提供一个public static void premain(String args, Instrumentation inst)或 public static void premain(String args) 方法。

当在命令行启动该代理jar时,VM会根据manifest中指定的代理类,使用于main类相同的系统类加载器(即ClassLoader.getSystemClassLoader()获得的加载器)加载代理类。在执行main方法前执行premain()方法。如果premain(String args, Instrumentation inst)和premain(String args)同时存在时,优先使用前者。其中方法参数args即命令中的options,类型为String(注意不是String[]),因此如果需要多个参数,需要在方法中自己处理(比如用";"分割多个参数之类);inst是运行时由VM自动传入的Instrumentation实例,可以用于获取VM信息。


premain简单实例

1、先定义一个简单的Hello实例

public classTestMain {

public static void main(String[]args){

People people=newPeople();

people.sayHello();

}

}

其中 People类定义如下:

public classPeople {

public voidsayHello(){

System.out.println("hello !!!!");

}

}

2、编写一个MyAgent实例:

public classMyAgent {

/**

* 该方法是一个类作为agent类必备的

* @paramagentArgs

* @paraminst

*/

public static void premain(String agentArgs,Instrumentation inst){

//加入ClassFileTransfomer

inst.addTransformer(new PeopleClassFileTransformer());

}

}

PeopleClassFileTransformer类定义如下,主要通过javassist修改sayHello方法字节码:

public classPeopleClassFileTransformerimplementsClassFileTransformer {

/**

* 通过javassist修改字节码

* @paramloader

* @paramclassName

* @paramclassBeingRedefined

* @paramprotectionDomain

* @paramclassfileBuffer

* @return

* @throws IllegalClassFormatException

*/

@Override

public byte[]transform(ClassLoader loader,String className,Class classBeingRedefined,ProtectionDomain protectionDomain, byte[] classfileBuffer)throwsIllegalClassFormatException {

System.out.println("load class:"+className);

if("com/yao/intrumentation/People".equals(className)){

try{

//通过javassist修改sayHello方法字节码

CtClass ctClass= ClassPool.getDefault().get(className.replace('/','.'));

CtMethod sayHelloMethod=ctClass.getDeclaredMethod("sayHello");

sayHelloMethod.insertBefore("System.out.println(\"before sayHello----\");");

sayHelloMethod.insertAfter("System.out.println(\"after sayHello----\");");

returnctClass.toBytecode();

}catch(NotFoundException e) {

e.printStackTrace();

}catch(CannotCompileException e) {

e.printStackTrace();

}catch(IOException e) {

e.printStackTrace();

}

}

returnclassfileBuffer;

}

}

然后编写MAINIFEST.MF文件如下:

Manifest-Version: 1.0

Premain-Class:: com.yao.intrumentation.MyAgent

Created-By: 1.8.0_121

打包MyAgent文件成MyAgent.jar

3、在ideal运行配置界面中VM options输入-javaagent:E:/Java_Web/JavaSPI-master/target/classes/myagent.jar,即MyAgent.jar路径;


java instrument学习总结_第1张图片

4、运行结果如下:


java instrument学习总结_第2张图片

你可能感兴趣的:(java instrument学习总结)