javassist简介

一个比较好的例子:http://yucaifu1989.iteye.com/blog/1850500

比较好的文档:

 

Javassist是一个开源的java字节码操作工具,主要是对已经编译好的class文件进行修改和处理,这里我写了一个简单的说明,复杂的请去看www.javassist.com的官方文档。

亲测实例

1、首先去官网下载jar http://jboss-javassist.github.io/javassist/ 里面有例子。

2、同样的使用使用jd-gui打开要修改的jar,找到要修改的类名、方法名。

3、在2的基础上开始写修改代码

package start;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class Test1 {
public static void main(String[] args) throws Exception {
//创建类池(就是jar包),用来加载类
ClassPool cp=ClassPool.getDefault();
//jar包所在位置,如果这句代码不写,下面引用的类就是项目中引用的类
cp.insertClassPath("e:/checkLicense-3-3.1.jar");
//获取要修改的具体类,注意是完整路径包括类名
CtClass cc=cp.get("com.primeton.licensemanager.checklicense.LicenseCheckManager");
 
//获取要修改的具体方法
CtMethod cm=cc.getDeclaredMethod("checkHardware");
//开始对方法进行修改,这里是往方法的最前面插入了一条语句
cm.insertBefore("if(true)return;");
//保存,执行后会在工程下生成一个新的class文件,刷新一下项目即可看到
cc.writeFile();
}
 
}

 

 

 

4、查看新生成的文件,将生成的新class文件替换jar包以前的class即可使用了。

 

这块有意思,编译器将true生成了1!=0了.....

 

在指定位置添加代码

// 在这个方法的182行添加关闭文件流的方法

method.insertAt(182, "fin.close();");

指定生成新class位置

ctClass.writeFile("path");


加入try cath块

addCatch()
addCatch() 指的是在方法中加入try catch 块,需要注意的是,必须在插入的代码中,加入return 值$e代表 异常值。比如:  
CtMethod m = ...;  
CtClass etype = ClassPool.getDefault().get("java.io.IOException");  
m.addCatch("{ System.out.println($e); throw $e; }", etype);  
实际代码如下:
try {  
    the original method body  
}  
catch (java.io.IOException e) {  
    System.out.println(e);  
    throw e;  
}

重写方法体

//获取要修改的具体方法

CtMethod cm=cc.getDeclaredMethod("checkHardware");
cm.setBody("System.out.println(\"\");");

cm.setBody();方法可以重新设置方法体的内容。

cm.setName();重新设置方法名字。

使用方法中的参数

Javassist也提供了一些特殊的变量来代表方法参 数:$1,$2,$args...要注意的是,插入的source文本中不能引用方法本地变量的声明,但是可以允许声明一个新的方法本地变量,除非在程序 编译时加入-g选项。

 

$0代表的是this,$1代表方法参数的第一个参数、$2代表方法参数的第二个参数,以此类推,$N代表是方法参数的第N个。例如:  

 

1.     //实际方法
2.     void move(int dx, int dy)   
3.     //javassist
4.     CtMethod m = cc.getDeclaredMethod("move");  
5.     //打印dx,和dy
6.     m.insertBefore("{ System.out.println($1); System.out.println($2); }");  
7.     注意:如果javassist改变了$1的值,那实际参数值也会改变。

1. $args 指的是方法所有参数的数组,类似Object[],如果参数中含有基本类型,则会转成其包装类型。需要注意的时候,$args[0]对应的是$1,而不是$0,$0!=$args[0],$0=this

 

 

使用类中定义的属性(字段)

$0 是代表this 也就是对象自己,所以直接使用 $0.字段 进行赋值或者使用即可。

例如字段名字叫 status 就可以写成 $0.status=1;

 

注意:目前可以确定用这种方式对字段进行赋值是没问题的,使用字段的方法还没有测试过。

使用类中定义的方法

与使用字段方法相似,$0.方法名

例如:方法名字叫 get() 就可以写成 $0.get();

修改构造方法

//获取构造方法集合,也可以指定获取指定参数的构造方法

CtClass cc=....;

CtConstructor[] ctc= cc.getConstructors();

 

//使用某个构造方法,与普通方法操作相同

ctc[0].insertAfter("{return ;}");