1、Javassist操作类的常用方法
测试代码:
@Test
public void test01() throws Exception {
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 获取user类对象
// com.maple.testJavassist.User只是一个普通的测试类
CtClass userClass = pool.get("com.maple.testJavassist.User");
// 转化为字节码
byte[] bytecode = userClass.toBytecode();
System.out.println("User.class字节码为:" + Arrays.toString(bytecode));
// 获取全类名
System.out.println("User类全类名为:" + userClass.getName());
// 获取类名
System.out.println("User类名为:" + userClass.getSimpleName());
// 获取接口
System.out.println("User类名为:" + userClass.getInterfaces());
//获取父类
System.out.println("User类名为:" + userClass.getSuperclass());
}
测试结果:
2、javassist新建Method方法
测试代码:
@Test
public void test02() throws Exception {
/*************************************
* 创建新增方法
* ***********************************/
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 获取user类对象
// com.maple.testJavassist.User只是一个普通的测试类
CtClass userClass = pool.get("com.maple.testJavassist.User");
// 在User类中新增一个方法
/**
* 新增一个add(int a,int b)方法
* public int add (int a ,int b){
* return a+b;
* }
*/
CtMethod newMethod = new CtMethod(
CtClass.intType, //方法返回值类型
"add", //方法名
//方法参数类型
new CtClass[] { CtClass.intType, CtClass.intType },
userClass//这个新方法将要添加到user类上
);
newMethod.setModifiers(Modifier.PUBLIC);//设置方法修饰符
newMethod.setBody("{return $1+$2;}");//添加方法体
//将新方法加到user类中注意这里操作的只是字节码
userClass.addMethod(newMethod);
/*************************************
* 反射新增方法
* ***********************************/
//通过反射调用新添加的类
Class<?>clazz = userClass.toClass();
//获取一个user实例对象
User userNewInstance = (User)clazz.newInstance();
//获取新增方法
Method m = clazz.getDeclaredMethod("add", int.class,int.class);
Object result = m.invoke(userNewInstance, 100,200);
System.out.println("执行add方法结果为"+result);
}
测试结果:
注意:这里对其中的newMethod.setBody("{return $1+$2;}");
做出解释
为什么要采用$1,和$2呢?
首先先说明$1和$2代表的是add(int a ,int b)的两个形参,是为了操作字节码的时候代表形参的。以下是常用的一些操作方法时的占位符
以下表格的例子都以add(int a,int b)为原型
占位符 | 解释 |
---|---|
$0 | 表示方法中的隐式参数this |
$1,$2… | 分别依次代表方法中的参数 例 int a,和 int b |
\args | 表示所有形式参数的数组对象,args[0]代表 $1,args[1]代表$2依次类推 |
$$ | 所有方法参数的简写 例 add($$)=add(\$1,\$2) |
$cflow | 方法调用的深度,可以理解为递归调用时处在被调用的第几步 |
$r | 方法返回值的类型 |
$_ | 方法返回值 |
addCatch() | 方法中加入try catch 块,$e代表异常对象 |
$class | this的类型(Class) 也就是$0的类型 |
$sig | 方法参数的类型数组 |
3、Javassist修改类中已有的方法
测试代码
@Test
public void test03() throws Exception {
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 获取user类对象
// com.maple.testJavassist.User只是一个普通的测试类
CtClass userClass = pool.get("com.maple.testJavassist.User");
//获取hello方法对象
CtMethod hello = userClass.getDeclaredMethod("hello", null);
hello.insertBefore("System.out.println(\"insertBefore==>在hello方法体的前面插入\");");
hello.insertAfter("System.out.println(\"insertAfter==>在hello方法体的最后插入\");");
hello.insertAt(6, "System.out.println(\"insertAt==>在第6行插入\");");
/*************************************
* 反射测试方法
* ***********************************/
//通过反射调用新添加的类
Class<?>clazz = userClass.toClass();
//获取一个user实例对象
User userNewInstance = (User)clazz.newInstance();
//获取新增方法
Method m = clazz.getDeclaredMethod("hello");
m.invoke(userNewInstance);
}
测试结果
4、Javassit新建属性以及setter和getter方法
测试代码
@Test
public void test04() throws Exception {
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 获取user类对象
// com.maple.testJavassist.User只是一个普通的测试类
CtClass userClass = pool.get("com.maple.testJavassist.User");
//创建一个属性 private String name;
CtField f1 = new CtField(
pool.get("java.lang.String"),//属性数据类型
"name", //属性名
userClass
);//属性将要加在哪个类上
//添加属性
userClass.addField(f1);
//快速创建该新增属性f1的setter和getter方法
userClass.addMethod(CtNewMethod.setter("setName", f1));
userClass.addMethod(CtNewMethod.getter("getName", f1));
}
5、Javassist构造函数操作
具体测试和之前反射测试相同这里只列出相关API的使用和注解
测试代码:
@Test
public void test05() throws Exception {
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 获取user类对象
// com.maple.testJavassist.User只是一个普通的测试类
CtClass userClass = pool.get("com.maple.testJavassist.User");
//获取所有的构造方法
CtConstructor[] constructors = userClass.getConstructors();
for (CtConstructor c : constructors) {
c.insertBefore("insertBefore");
c.insertAfter("insertBefore");
c.insertAt(8, "insertAt");
}
}
6、Javassist注解操作
测试代码
自定义注解Level.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Level {
String value();
}
User.java
User类有以下的注解
@Level("会员")
public class User {
public void hello() {
System.out.println("hello方法你好");
}
}
测试程序
@Test
public void test06() throws Exception {
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 获取user类对象
// com.maple.testJavassist.User只是一个普通的测试类
CtClass userClass = pool.get("com.maple.testJavassist.User");
Level level = (com.maple.testJavassist.Level) userClass.getAnnotation(Level.class);
System.out.println(level.value());
}
测试结果
小结:
本篇文件分别介绍了javassit的一些常用API,包括对类的操作,如何新增方法,如何对已有方法进行修改,如何新增属性,如何快速创建setter和getter方法,操作构造器,注解的操作,这些都是javassist的常用API,要想了解更多更细的API可以参见javassist的官网查看官方文档