javaassist入门(一)-no such field:

来源:互联网 发布:2017双十一大数据分析 编辑:程序博客网 时间:2024/06/03 18:10

构建javaassist入门实例:


场景;

监控每个方法的执行时间

方式:

通过javaassist实现


代码:

package com.sirding;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.Instrumentation;public class MyAgent {private static Instrumentation inst = null;public static void premain(String agentArgs, Instrumentation _inst){System.out.println("PerfMonAgent.premian() was called.");inst = _inst;ClassFileTransformer trans = new MyTransform();System.out.println("Adding a PerfMonXformer instance to the JVM.");inst.addTransformer(trans);}}


package com.sirding;import java.io.ByteArrayInputStream;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.security.ProtectionDomain;import javassist.CannotCompileException;import javassist.ClassPool;import javassist.CtBehavior;import javassist.CtClass;import javassist.NotFoundException;public class MyTransform implements ClassFileTransformer{@Overridepublic byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {byte[] transformed = null;System.out.println("Transforming " + className);ClassPool pool = ClassPool.getDefault();CtClass cl = null;try {cl = pool.makeClass(new ByteArrayInputStream(classfileBuffer));if(!cl.isInterface()) {CtBehavior[] methods = cl.getDeclaredBehaviors();for(CtBehavior method : methods){doMethod(method);}transformed = cl.toBytecode();}} catch (Exception e) {e.printStackTrace();}finally {if(cl != null){cl.detach();}}return transformed;}private void doMethod(CtBehavior method) throws NotFoundException, CannotCompileException {if("myTest".equalsIgnoreCase(method.getName())){//添加局部变量,如果不同过addLocalVariable设置,在调用属性时将出现compile error: no such field: startTimemethod.addLocalVariable("startTime", CtClass.longType);method.insertBefore("System.out.println(startTime);");method.insertBefore("startTime = System.currentTimeMillis();");//method.insertBefore("long startTime = System.currentTimeMillis();System.out.println(startTime);");method.insertBefore("System.out.println(\"insert before ......\");");method.insertAfter("System.out.println(\"leave " + method.getName() + " and time is :\" + (System.currentTimeMillis() - startTime));");}}}

pom.xml用于生成jar

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.sirding</groupId><artifactId>java-inst</artifactId><version>1</version><packaging>jar</packaging><name>java-inst</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.20.0-GA</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>2.4</version><configuration><archive><manifestEntries>
<!-- 重点配置 --><Premain-Class>com.sirding.MyAgent</Premain-Class>
<!-- 依赖javaassit包路径 --><Boot-Class-Path>自己的系统路径/Maven/repo_3.3.3/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar</Boot-Class-Path></manifestEntries></archive></configuration></plugin> <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><skip>true</skip></configuration></plugin><plugin>        <groupId>org.apache.maven.plugins</groupId>        <artifactId>maven-compiler-plugin</artifactId>        <version>3.5.1</version>        <configuration>            <source>1.8</source>            <target>1.8</target>        </configuration>    </plugin></plugins></build></project>

通过maven将上述的项目打java-inst.jar

编写测试类

public class Test{public static void main(String[] args){System.out.println("hello world");new Test().myTest();}public void myTest(){System.out.println("===============================================");}}

将Test.java java-inst.jar放在同一个文件中,执行如下命令

javac Test.java 生成Test.class

java -javaassist:java-inst.jar Test

C:\yrtz\test\aa>java -javaagent:java-inst-1.jar TestPerfMonAgent.premian() was called.Adding a PerfMonXformer instance to the JVM.Transforming java/lang/invoke/MethodHandleImplTransforming java/lang/invoke/MethodHandleImpl$1Transforming java/lang/invoke/MethodHandleImpl$2Transforming java/util/function/FunctionTransforming java/lang/invoke/MethodHandleImpl$3Transforming java/lang/invoke/MethodHandleImpl$4Transforming java/lang/ClassValueTransforming java/lang/ClassValue$EntryTransforming java/lang/ClassValue$IdentityTransforming java/lang/ClassValue$VersionTransforming java/lang/invoke/MemberName$FactoryTransforming java/lang/invoke/MethodHandleStaticsTransforming java/lang/invoke/MethodHandleStatics$1Transforming sun/misc/PostVMInitHookTransforming sun/usagetracker/UsageTrackerClientTransforming java/util/concurrent/atomic/AtomicBooleanTransforming sun/usagetracker/UsageTrackerClient$1Transforming sun/usagetracker/UsageTrackerClient$4Transforming sun/usagetracker/UsageTrackerClient$2Transforming java/lang/ProcessEnvironmentTransforming java/lang/ProcessEnvironment$NameComparatorTransforming java/lang/ProcessEnvironment$EntryComparatorTransforming java/util/Collections$UnmodifiableMapTransforming java/lang/ProcessEnvironment$CheckedEntrySetTransforming java/util/HashMap$EntrySetTransforming java/lang/ProcessEnvironment$CheckedEntrySet$1Transforming java/util/HashMap$EntryIteratorTransforming java/util/HashMap$HashIteratorTransforming java/lang/ProcessEnvironment$CheckedEntryTransforming sun/usagetracker/UsageTrackerClient$3Transforming java/io/FileOutputStream$1Transforming sun/launcher/LauncherHelperTransforming sun/misc/URLClassPath$FileLoader$1Transforming TestTransforming sun/launcher/LauncherHelper$FXHelperTransforming java/lang/Class$MethodArrayhello worldinsert before ......1492659861901===============================================leave myTest and time is :24Transforming java/lang/ShutdownTransforming java/lang/Shutdown$Lock

可以看到“leave myTest and time is :24”通过静态代理,动态的更新执行的method的二进制编码,有效的统计方法执行的时间

PS:

如果在动态添加局部变量时出现如下异常

javassist.CannotCompileException: [source error] no such field: startTime        at javassist.CtBehavior.insertAfter(CtBehavior.java:877)        at javassist.CtBehavior.insertAfter(CtBehavior.java:792)        at com.sirding.Perfmonxformer.doMethod(Perfmonxformer.java:49)        at com.sirding.Perfmonxformer.transform(Perfmonxformer.java:27)        at sun.instrument.TransformerManager.transform(TransformerManager.java:188)        at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)        at java.lang.ClassLoader.defineClass1(Native Method)        at java.lang.ClassLoader.defineClass(ClassLoader.java:763)        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)        at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)        at java.net.URLClassLoader.access$100(URLClassLoader.java:73)        at java.net.URLClassLoader$1.run(URLClassLoader.java:368)        at java.net.URLClassLoader$1.run(URLClassLoader.java:362)        at java.security.AccessController.doPrivileged(Native Method)        at java.net.URLClassLoader.findClass(URLClassLoader.java:361)        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)        at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)Caused by: compile error: no such field: startTime        at javassist.compiler.TypeChecker.fieldAccess(TypeChecker.java:845)        at javassist.compiler.TypeChecker.atFieldRead(TypeChecker.java:803)        at javassist.compiler.TypeChecker.atMember(TypeChecker.java:988)        at javassist.compiler.JvstTypeChecker.atMember(JvstTypeChecker.java:66)        at javassist.compiler.ast.Member.accept(Member.java:39)        at javassist.compiler.TypeChecker.atBinExpr(TypeChecker.java:329)        at javassist.compiler.ast.BinExpr.accept(BinExpr.java:41)        at javassist.compiler.TypeChecker.atPlusExpr(TypeChecker.java:371)        at javassist.compiler.TypeChecker.atBinExpr(TypeChecker.java:312)        at javassist.compiler.ast.BinExpr.accept(BinExpr.java:41)        at javassist.compiler.JvstTypeChecker.atMethodArgs(JvstTypeChecker.java:221)        at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:735)        at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:695)        at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:157)        at javassist.compiler.ast.CallExpr.accept(CallExpr.java:46)        at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:242)        at javassist.compiler.CodeGen.atStmnt(CodeGen.java:330)        at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)        at javassist.compiler.Javac.compileStmnt(Javac.java:569)        at javassist.CtBehavior.insertAfterAdvice(CtBehavior.java:892)        at javassist.CtBehavior.insertAfter(CtBehavior.java:851)        ... 18 more

确保 你在执行method.addLocalVariable("startTime", CtClass.longType);操作,对要使用的局部变量进行了定义。


0 0
原创粉丝点击