官方主页:http://www.csg.is.titech.ac.jp/~chiba/javassist/
Javassist,Cglib等是一些代码增强工具,在运行时刻进行Java字节码增强,虽然速度上稍微慢一点点,但是带来的是代码的简洁,今天用Javassist进行代码增强。
代码:
TestBean.java
- package javassist.sample;
- public abstract class TestBean {
- public String field;
- public abstract String getM();
- public abstract void setF(String f);
- public String getF() {
- return this.field;
- }
- }
TestByteCode.java
- package javassist.sample;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtConstructor;
- import javassist.CtMethod;
- public class TestByteCode {
- public static void main(String[] args) throws Exception {
- ClassPool pool = ClassPool.getDefault();
- CtClass pt = pool.makeClass("asdf", pool.get("javassist.sample.TestBean"));
- CtMethod method1 = new CtMethod(pool.get("java.lang.String"), "getM", null, pt);
- method1.setBody("{return /"你好/";}");
- pt.addMethod(method1);
- CtConstructor cc = new CtConstructor(null, pt);
- cc.setBody("this.field=/"why?/";");
- pt.addConstructor(cc);
- CtMethod method2 = new CtMethod(CtClass.voidType, "setF",
- new CtClass[] { pool.get("java.lang.String") }, pt);
- method2.setBody("{this.field=$1;}");
- pt.addMethod(method2);
- Class<?> c = pt.toClass();
- TestBean bean = (TestBean) c.newInstance();
- System.out.println(bean.getM());
- System.out.println(bean.getF());
- bean.setF("setf");
- System.out.println(bean.getF());
- }
- }
输出为:
你好
why?
setf
可以看到实现了动态的构造,动态实现抽象函数。在进行代码自动化项目中,能够使用字节码增强将大大提高代码的质量,和减少代码的数量。
再看一个例子:
A.java
- package javassist.demo;
- public class A {
- public void method() {
- for (int i = 0; i < 1000000; i++) {
- }
- System.out.println("method1");
- }
- }
JavassistTest.java
- package javassist.demo;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtMethod;
- import javassist.CtNewMethod;
- public class JavassistTest {
- public static void main(String[] args) throws Exception {
- // 用于取得字节码类,必须在当前的classpath中,使用全称
- CtClass ctClass = ClassPool.getDefault().get("javassist.demo.A");
- // 需要修改的方法名称
- String mname = "method";
- 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);
- // 类已经更改,注意不能使用A a=new A();,因为在同一个classloader中,不允许装载同一个类两次
- A a = (A) ctClass.toClass().newInstance();
- a.method();
- }
- }
资料:
http://tsaijun.spaces.live.com/blog/cns!C9F557E0FD3838C1!121.entry