javaassist入门(一)-no such field:

无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里以跳转到教程。

构建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{

	@Override
	public 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: startTime
			method.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

 

 


	4.0.0

	com.sirding
	java-inst
	1
	jar

	java-inst
	http://maven.apache.org

	
		UTF-8
	

	
		
			junit
			junit
			4.12
			test
		

		
			org.javassist
			javassist
			3.20.0-GA
		

	


	
		
			
				org.apache.maven.plugins
				maven-jar-plugin
				2.4
				
					
						
							
							
								com.sirding.MyAgent
							
							
								com.sirding.MyAgent
							
							
							
								自己的系统路径/Maven/repo_3.3.3/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar
							
						
					
				
			
			 
			
				org.apache.maven.plugins
				maven-surefire-plugin
				
					true
				
			
			
			
		        org.apache.maven.plugins
		        maven-compiler-plugin
		        3.5.1
		        
		            1.8
		            1.8
		        
    		
		
	


							
								自己的系统路径/Maven/repo_3.3.3/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar
							
						
					
				
			
			 
			
				org.apache.maven.plugins
				maven-surefire-plugin
				
					true
				
			
			
			
		        org.apache.maven.plugins
		        maven-compiler-plugin
		        3.5.1
		        
		            1.8
		            1.8
		        
    		
		
	


通过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 Test
PerfMonAgent.premian() was called.
Adding a PerfMonXformer instance to the JVM.
Transforming java/lang/invoke/MethodHandleImpl
Transforming java/lang/invoke/MethodHandleImpl$1
Transforming java/lang/invoke/MethodHandleImpl$2
Transforming java/util/function/Function
Transforming java/lang/invoke/MethodHandleImpl$3
Transforming java/lang/invoke/MethodHandleImpl$4
Transforming java/lang/ClassValue
Transforming java/lang/ClassValue$Entry
Transforming java/lang/ClassValue$Identity
Transforming java/lang/ClassValue$Version
Transforming java/lang/invoke/MemberName$Factory
Transforming java/lang/invoke/MethodHandleStatics
Transforming java/lang/invoke/MethodHandleStatics$1
Transforming sun/misc/PostVMInitHook
Transforming sun/usagetracker/UsageTrackerClient
Transforming java/util/concurrent/atomic/AtomicBoolean
Transforming sun/usagetracker/UsageTrackerClient$1
Transforming sun/usagetracker/UsageTrackerClient$4
Transforming sun/usagetracker/UsageTrackerClient$2
Transforming java/lang/ProcessEnvironment
Transforming java/lang/ProcessEnvironment$NameComparator
Transforming java/lang/ProcessEnvironment$EntryComparator
Transforming java/util/Collections$UnmodifiableMap
Transforming java/lang/ProcessEnvironment$CheckedEntrySet
Transforming java/util/HashMap$EntrySet
Transforming java/lang/ProcessEnvironment$CheckedEntrySet$1
Transforming java/util/HashMap$EntryIterator
Transforming java/util/HashMap$HashIterator
Transforming java/lang/ProcessEnvironment$CheckedEntry
Transforming sun/usagetracker/UsageTrackerClient$3
Transforming java/io/FileOutputStream$1
Transforming sun/launcher/LauncherHelper
Transforming sun/misc/URLClassPath$FileLoader$1
Transforming Test
Transforming sun/launcher/LauncherHelper$FXHelper
Transforming java/lang/Class$MethodArray
hello world
insert before ......
1492659861901
===============================================
leave myTest and time is :24
Transforming java/lang/Shutdown
Transforming 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);操作,对要使用的局部变量进行了定义。

 

 

 

你可能感兴趣的:(ShowMeCode)