天天看點

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

常見的位元組碼操作類庫

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

https://github.com/jboss-javassist/javassist

JAVAssist的API詳解

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

Intellij IDEA 添加jar包的三種方式

用javassist生成一個新的類

import javassist.*;

/**
 * 測試用javassist生成一個新的類
 */
public class Demo01 {

    public static void main(String[] args) throws Exception{

        // 擷取類池
        ClassPool pool = ClassPool.getDefault();

        // 建立新類
        CtClass cc = pool.makeClass("test.bean.Emp");

        // 建立屬性
        CtField f1 = CtField.make("private int empno;", cc);
        CtField f2 = CtField.make("private String ename;", cc);
        cc.addField(f1);
        cc.addField(f2);

        // 建立方法
        CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
        CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno = empno;}", cc);
        cc.addMethod(m1);
        cc.addMethod(m2);

        // 添加構造器
        CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc);
        constructor.setBody("{this.empno=empno; this.ename=ename;}");
        cc.addConstructor(constructor);

        cc.writeFile("./");  // 将上面建立好的類寫入指定檔案夾下
        System.out.println("Successful !!!");
    }
}
           

生成.class檔案

XJad反編譯工具

找到位元組碼所在目錄打開即可

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解
Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

JAVAssist庫的API詳解

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

test.Emp

package test;

public class Emp {
    private int empno;
    private String ename;

    public void sayHello(int a){
        System.out.println("sayHello " + a);
    }

    public int getEmpno() {
        return empno;
    }

    public void setEmpno(int empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Emp(int empno, String ename) {
        this.empno = empno;
        this.ename = ename;
    }

    public Emp(){

    }
}
           

Demo

package test;

import javassist.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 測試用javassist API
 */
public class Demo02 {

    /**
     * 處理類的基本用法
     */
    public static void test01() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        // 加載已有類
        CtClass cc = pool.get("test.Emp");

        byte[] bytes = cc.toBytecode();
        System.out.println(Arrays.toString(bytes));

        System.out.println(cc.getName());  // 擷取類名
        System.out.println(cc.getSimpleName());  // 擷取簡要類名
        System.out.println(cc.getSuperclass());  // 獲得父類
        System.out.println(cc.getInterfaces());  // 獲得接口,得到的是一個數組
    }

    /**
     * 測試添加新的方法
     */
    public static void test02() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("test.Emp");

//        CtMethod m = CtNewMethod.make("public int add(int a, int b){return a+b;}", cc);

        // 聲明一個方法
        // (傳回類型, 方法名, 參數類型, 添加到哪個類)
        CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, cc);
        // 添加方法體
        m.setModifiers(Modifier.PUBLIC);  // 通路權限
        m.setBody("{System.out.println(\"add fun\"); return $1 + $2;}");

        cc.addMethod(m);

        // 通過反射調用新生成的方法
        Class clz = cc.toClass();
        Object obj = clz.getConstructor().newInstance();  // 建立Emp對象

        Method method = clz.getDeclaredMethod("add", int.class, int.class);
        Object result = method.invoke(obj, 200, 300);
        System.out.println(result);

    }

    /**
     * 修改已有方法的資訊,修改方法體的内容
     */
    public static void test03() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("test.Emp");

        CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[]{CtClass.intType});
        cm.insertBefore("System.out.println($1); System.out.println(\"start !!!\");");
        // 在原檔案的指定行數添加代碼
        cm.insertAt(9, "int b = 3;System.out.println(\"b = \" + b);");
        cm.insertAfter("System.out.println(\"end !!!\");");

        // 通過反射調用新生成的方法
        Class clz = cc.toClass();
        Object obj = clz.getConstructor().newInstance();  // 建立Emp對象

        Method method = clz.getDeclaredMethod("sayHello", int.class);
        method.invoke(obj, 300);

    }

    /**
     * 屬性的操作
     */
    public static void test04() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("test.Emp");

//        CtField f1 = CtField.make("private int salary = 1000;", cc);
        CtField f1 = new CtField(CtClass.intType,"salary",cc);
        f1.setModifiers(Modifier.PRIVATE);
        cc.addField(f1, "1000");

        // 增加相應的set/get方法
        cc.addMethod(CtNewMethod.getter("getSalary", f1));
        cc.addMethod(CtNewMethod.setter("setSalary", f1));

        CtField f2 = cc.getDeclaredField("salary");  // 擷取指定屬性
        System.out.println(f2.getName());

        // 反射
        Class clz = cc.toClass();
//        Emp emp = (Emp)clz.getConstructor().newInstance();
        Object emp = clz.getConstructor().newInstance();

        Field sf = clz.getDeclaredField("salary");
        sf.setAccessible(true);    // 設定這個屬性不需要做安全檢查了,可以直接通路
        System.out.println(sf.get(emp));

    }

    /**
     * 構造器方法的操作
     */
    public static void test05() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("test.Emp");

        CtConstructor[] cs = cc.getConstructors();
        for (CtConstructor c: cs) {
            System.out.println(c.getLongName());
//            c.insertBefore(...);
        }


    }

    public static void main(String[] args) throws Exception{

//        test01();  // testXX 不能同時調用
//        test02();
//        test03();
//        test04();
        test05();
    }
}
           

Output

test01

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

test02

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

test03

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

test04

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解

test05

Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解
Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解
Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解
Java位元組碼操作(JAVAassist)常見的位元組碼操作類庫JAVAssist的API詳解JAVAssist庫的API詳解