它类似一种更低级,更松耦合的AOP,可以从底层来改变一个类的行为,你可以由此产生无限的遐想。
接下来要做的事情,就是计算一个方法所花的时间,通常我们会在代码这么写:
在方法开始开头加入long stime = System.nanoTime();
在方法结尾通过System.nanoTime()-stime得出方法所花时间,你不得不在你想监控的每个方法中写入重复的代码,
好一点的情况,你可以用AOP来干这事,但总是感觉有点别扭,这种profiler的代码还是打包在你的项目中,
java instrument使得这更干净。
1) 写agent类
2)写ClassFileTransformer类
上面两个类就是agent的核心了,jvm启动时并会在应用加载前会调用 PerfMonAgent.premain, 然后PerfMonAgent.premain中实例化了一个定制的ClassFileTransforme即 PerfMonXformer
并通过inst.addTransformer(trans);把PerfMonXformer的实例加入Instrumentation实例(由jvm传入),这就使得应用中的类加载的时候, PerfMonXformer.transform都会被调用,你在此方法中
可以改变加载的类,真的有点神奇,为了改变类的字节码,我使用了jboss的javassist,虽然你不一定要这么用,但jboss的javassist真的很强大,让你很容易的改变类的字节码。在上面的方法中
我通过改变类的字节码,在每个类的方法入口中加入了long stime = System.nanoTime();,在方法的出口加入了System.out.println("methodClassName.methodName:"+(System.nanoTime()-stime));
3) 打包agent
对于agent的打包,有点讲究,
3.1)
jar的META-INF/MANIFEST.MF加入Premain-Class: xx, xx在此语境中就是我们的agent类,即org.toy.PerfMonAgent
3.2)
如果你的agent类引入别的包,需使用Boot-Class-Path: xx,xx在此语境中就是上面提到的jboss javassit 即 /home/pwlazy/.m2/repository/javassist/javassist/3.8.0 .GA/javassist-3.8.0.GA.jar
下面附上maven 的pom
最终打成一个包toy-inst-1.0-SNAPSHOT.jar
4)打包应用
随便写个应用
最终打成一个包toy-1.0-SNAPSHOT.jar
5)执行命令
java选项中有-javaagent:xx,xx就是你的agent jar,java通过此选项加载agent,由agent来监控classpath下的应用。
最后的执行结果:
我们由执行结果可以看出执行顺序以及通过改变org.toy.App的字节码加入监控代码确实生效了。
你也可以发现通过instrment实现agent是的监控代码和应用代码完全隔离了。
最新评论