英语单词

java instrument的使用

推荐访问: 如何用Instruments 检验app

Java在1.5引入java.lang.instrument,可以由此实现一个Java agent,通过此agent来修改类的字节码即改变一个类。本文中,会通过java instrument 实现一个简单的profiler。当然instrument并不限于profiler,instrument可以做很多事情,

它类似一种更低级,更松耦合的AOP,可以从底层来改变一个类的行为,可以由此产生无限的遐想。
接下来要做的事情,就是计算一个方法所花的时间,通常我们会在代码这么写: 
在方法开始开头加入long stime = System.nanoTime();
在方法结尾通过System.nanoTime()-stime得出方法所花时间,不得不在想监控的每个方法中写入重复的代码,
好一点的情况,可以用AOP来干这事,但总是感觉有点别扭,这种profiler的代码还是打包在项目中,

java instrument使得这更干净。

 

1) 写agent类

[java] view plain copy

1. package org.toy;  

2. import java.lang.instrument.Instrumentation;  

3. import java.lang.instrument.ClassFileTransformer;  

4. public class PerfMonAgent {  

5.     static private Instrumentation inst = null;  

6.     /** 

7.      * This method is called before the application’s main-method is called, 

8.      * when this agent is specified to the Java VM. 

9.      **/  

10.     public static void premain(String agentArgs, Instrumentation _inst) {  

11.         System.out.println("PerfMonAgent.premain() was called.");  

12.         // Initialize the static variables we use to track information.  

13.         inst = _inst;  

14.         // Set up the class-file transformer.  

15.         ClassFileTransformer trans = new PerfMonXformer();  

16.         System.out.println("Adding a PerfMonXformer instance to the JVM.");  

17.         inst.addTransformer(trans);  

18.     }  

19. }  

2)写ClassFileTransformer类
 [java] view plain copy

1. package org.toy;  

2. import java.lang.instrument.ClassFileTransformer;  

3. import java.lang.instrument.IllegalClassFormatException;  

4. import java.security.ProtectionDomain;  

5. import javassist.CannotCompileException;  

6. import javassist.ClassPool;  

7. import javassist.CtBehavior;  

8. import javassist.CtClass;  

9. import javassist.NotFoundException;  

10. import javassist.expr.ExprEditor;  

11. import javassist.expr.MethodCall;  

12. public class PerfMonXformer implements ClassFileTransformer {  

13.     public byte[] transform(ClassLoader loader, String className,  

14.             Class<?> classBeingRedefined, ProtectionDomain protectionDomain,  

15.             byte[] classfileBuffer) throws IllegalClassFormatException {  

16.         byte[] transformed = null;  

17.         System.out.println("Transforming " + className);  

18.         ClassPool pool = ClassPool.getDefault();  

19.         CtClass cl = null;  

20.         try {  

21.             cl = pool.makeClass(new java.io.ByteArrayInputStream(  

22.                     classfileBuffer));  

23.             if (cl.isInterface() == false) {  

24.                 CtBehavior[] methods = cl.getDeclaredBehaviors();  

25.                 for (int i = 0; i < methods.length; i++) {  

26.                     if (methods[i].isEmpty() == false) {  

27.                         doMethod(methods[i]);  

28.                     }  

29.                 }  

30.                 transformed = cl.toBytecode();  

31.             }  

32.         } catch (Exception e) {  

33.             System.err.println("Could not instrument  " + className  

34.                     + ",  exception : " + e.getMessage());  

35.         } finally {  

36.             if (cl != null) {  

37.                 cl.detach();  

38.             }  

39.         }  

40.         return transformed;  

41.     }  

42.     private void doMethod(CtBehavior method) throws NotFoundException,  

43.             CannotCompileException {  

44.         // method.insertBefore("long stime = System.nanoTime();");  

45.         // method.insertAfter("System.out.println(/"leave "+method.getName()+" and time:/"+(System.nanoTime()-stime));");  

46.         method.instrument(new ExprEditor() {  

47.             public void edit(MethodCall m) throws CannotCompileException {  

48.                 m  

49.                         .replace("{ long stime = System.nanoTime(); $_ = $proceed($$); System.out.println(/""  

50.                                 + m.getClassName()+"."+m.getMethodName()  

51.                                 + ":/"+(System.nanoTime()-stime));}");  

52.             }  

53.         });  

54.     }  

55. }  


上面两个类就是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

[xhtml] view plain copy

1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  

2.   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  

3.   <modelVersion>4.0.0</modelVersion>  

4.   <groupId>org.toy</groupId>  

5.   <artifactId>toy-inst</artifactId>  

6.   <packaging>jar</packaging>  

7.   <version>1.0-SNAPSHOT</version>  

8.   <name>toy-inst</name>  

9.   <url>http://maven.apache.org</url>  

10.   <dependencies>  

11.      <dependency>  

12.       <groupId>javassist</groupId>  

13.       <artifactId>javassist</artifactId>  

14.       <version>3.8.0.GA</version>  

15.     </dependency>  

16.     <dependency>  

17.       <groupId>junit</groupId>  

18.       <artifactId>junit</artifactId>  

19.       <version>3.8.1</version>  

20.       <scope>test</scope>  

21.     </dependency>  

22.   </dependencies>  

23.    

24.    <build>  

25.     <plugins>  

26.       <plugin>  

27.         <groupId>org.apache.maven.plugins</groupId>  

28.         <artifactId>maven-jar-plugin</artifactId>  

29.         <version>2.2</version>  

30.         <configuration>  

31.           <archive>  

32.             <manifestEntries>  

33.               <Premain-Class>org.toy.PerfMonAgent</Premain-Class>  

34.               <Boot-Class-Path>/home/pwlazy/.m2/repository/javassist/javassist/3.8.0.GA/javassist-3.8.0.GA.jar</Boot-Class-Path>  

35.             

36.             </manifestEntries>  

37.           </archive>  

38.         </configuration>  

39.       </plugin>  

40.        

41.       <plugin>  

42.        <artifactId>maven-compiler-plugin </artifactId >  

43.               <configuration>  

44.                   <source> 1.6 </source >  

45.                   <target> 1.6 </target>  

46.               </configuration>  

47.      </plugin>  

48.     </plugins>   

49.       

50.      

51.   </build>  

52.    

53. </project>  


Z终打成一个包toy-inst-1.0-SNAPSHOT.jar

4)打包应用
随便写个应用

[java] view plain copy

1. package org.toy;  

2. public class App {  

3.     public static void main(String[] args) {  

4.         new App().test();  

5.     }  

6.     public void test() {  

7.         System.out.println("Hello World!!");  

8.     }  

9. }  

   
Z终打成一个包toy-1.0-SNAPSHOT.jar

5)执行命令

[Pythonview plain copy

1. java -javaagent:target/toy-inst-1.0-SNAPSHOT.jar -cp  /home/pwlazy/work/projects/toy/target/toy-1.0-SNAPSHOT.jar org.toy.App   



java选项中有-javaagent:xx,xx就是agent jar,java通过此选项加载agent,由agent来监控classpath下的应用。

Z后的执行结果: 

[xhtml] view plain copy

1. PerfMonAgent.premain() was called.  

2. Adding a PerfMonXformer instance to the JVM.  

3. Transforming org/toy/App  

4. Hello World!!  

5. java.io.PrintStream.println:314216  

6. org.toy.App.test:540082  

7. Transforming java/lang/Shutdown  

8. Transforming java/lang/Shutdown$Lock  

9. java.lang.Shutdown.runHooks:29124  

10. java.lang.Shutdown.sequence:132768  

 由执行结果可以看出执行顺序以及通过改变org.toy.App的字节码加入监控代码确实生效了。

可以发现通过instrment实现agent是的监控代码和应用代码完全隔离了。

 


2017-07-10浏览次数:1012次
本文来源:https://m.yiqi.com/retiao/detail_37.html
热门标签:
分享到
上一篇:页面紧急升级_的原因
下一篇:iOS工具Instrument的使用
最新资讯
看过该文章的人还看过
java instrument的使用
java instrument工具
java instrument