Java動態程式設計之javassist
阿新 • • 發佈:2019-02-03
概述
Javassist是一款位元組碼編輯工具,可以直接編輯和生成Java生成的位元組碼,以達到對.class檔案進行動態修改的效果。熟練使用這套工具,可以讓Java程式設計更接近與動態語言程式設計。
教程
maven依賴
pom.xml
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency >
API講解
1、建立一個新的Class
ClassPool pool = ClassPool.getDefault();
//定義類
CtClass stuClass = pool.makeClass("com.ricky.Student");
當然,如果某個類已經存在,可以直接載入它,如下:
CtClass cc = pool.get("java.lang.String");
2、構造類成員變數
//id屬性
CtField idField = new CtField(CtClass.longType, "id", stuClass);
stuClass.addField(idField);
3、構造類方法
CtMethod getMethod = CtNewMethod.make("public int getAge() { return this.age;}", stuClass);
CtMethod setMethod = CtNewMethod.make("public void setAge(int age) { this.age = age;}", stuClass);
stuClass.addMethod(getMethod);
stuClass.addMethod(setMethod);
應用示例
1、動態構造一個Class
package com .ricky.codelab.javassist;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
/**
* 動態構造Class
* @author Ricky
*
*/
public class JavassistDemo {
public static void main(String[] args) throws CannotCompileException, IOException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
//定義類
CtClass stuClass = pool.makeClass("com.ricky.Student");
//載入類
// CtClass cc = pool.get(classname);
//id屬性
CtField idField = new CtField(CtClass.longType, "id", stuClass);
stuClass.addField(idField);
//name屬性
CtField nameField = new CtField(pool.get("java.lang.String"), "name", stuClass);
stuClass.addField(nameField);
//age屬性
CtField ageField = new CtField(CtClass.intType, "age", stuClass);
stuClass.addField(ageField);
CtMethod getMethod = CtNewMethod.make("public int getAge() { return this.age;}", stuClass);
CtMethod setMethod = CtNewMethod.make("public void setAge(int age) { this.age = age;}", stuClass);
stuClass.addMethod(getMethod);
stuClass.addMethod(setMethod);
// stuClass.writeFile("F:\\Practice_Demo");
Class<?> clazz = stuClass.toClass();
System.out.println("class:"+clazz.getName());
System.out.println("------------屬性列表------------");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getType()+"\t"+field.getName());
}
System.out.println("------------方法列表------------");
//方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method: methods){
System.out.println(method.getReturnType()+"\t"+method.getName()+"\t"+Arrays.toString(method.getParameterTypes()));
}
}
}
2、指定父類
package com.ricky.codelab.javassist;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.NotFoundException;
public class JavassistExtendDemo {
public static void main(String[] args) throws CannotCompileException, IOException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
//定義類
CtClass stuClass = pool.makeClass("com.ricky.Student");
//設定父類
stuClass.setSuperclass(pool.get("com.ricky.codelab.javassist.domain.Person"));
//hobbies屬性
CtField ageField = new CtField(pool.getCtClass("java.util.List"), "hobbies", stuClass);
stuClass.addField(ageField);
Class<?> clazz = stuClass.toClass();
System.out.println("class:"+clazz.getName());
System.out.println("------------屬性列表------------");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getType()+"\t"+field.getName());
}
System.out.println("------------方法列表------------");
//方法
Method[] methods = clazz.getMethods();
for (Method method: methods){
System.out.println(method.getReturnType()+"\t"+method.getName()+"\t"+Arrays.toString(method.getParameterTypes()));
}
}
}
3、動態注入程式碼
package com.ricky.codelab.javassist;
import java.io.IOException;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
/**
* 動態注入程式碼
*
* @author Ricky
*
*/
public class JavassistInsertDemo {
public static void main(String[] args) throws CannotCompileException, IOException, NotFoundException, InstantiationException, IllegalAccessException {
ClassPool pool = ClassPool.getDefault();
// 定義類
CtClass ctClass = pool.get("com.ricky.codelab.javassist.Calculator");
// 需要修改的方法名稱
String mname = "getSum";
CtMethod mold = ctClass.getDeclaredMethod(mname);
// 修改原有的方法名稱
String nname = mname + "$impl";
mold.setName(nname);
//建立新的方法,複製原來的方法
CtMethod mnew = CtNewMethod.copy(mold, mname, ctClass, null);
// 主要的注入程式碼
StringBuffer body = new StringBuffer();
body.append("{\nlong start = System.currentTimeMillis();\n");
// 呼叫原有程式碼,類似於method();($$)表示所有的引數
body.append(nname + "($$);\n");
body.append("System.out.println(\"Call to method " + mname
+ " took \" +\n (System.currentTimeMillis()-start) + " + "\" ms.\");\n");
body.append("}");
// 替換新方法
mnew.setBody(body.toString());
// 增加新方法
ctClass.addMethod(mnew);
Calculator calculator =(Calculator)ctClass.toClass().newInstance();
calculator.getSum(10000);
}
}
class Calculator {
public void getSum(long n) {
long sum = 0;
for (int i = 0; i < n; i++) {
sum += i;
}
System.out.println("n="+n+",sum="+sum);
}
}