美文网首页
操作字节码

操作字节码

作者: kanaSki | 来源:发表于2019-07-08 20:40 被阅读0次

    运行时操作字节码可以实现如下功能:
    1.动态生成新类
    2.动态改变某个类的结构(添加、删除、修改 新的属性/方法)

    优势:
    1.比反射开销小
    2、Javassist性能高于反射,低于ASM

    常用字节码操作类库:
    1、BCEL 深入JVM汇编语言进行类操作
    2、ASM 轻量级java字节码操作框架,直接涉及到JVM底层的操作和指令
    3、CGLIB 高性能,高质量的Code类库,基于ASM实现
    4、Javassist 性能较ASM差,与CGLIB差不多。但是使用简单,强调源码级别的工作。

    javassist的最外层API与Java反射包中API颇为类似。
    它主要由CtClass,CtMethod以及CtField几个类组成。用以执行和JDK反射API中java.lang.Class,java.lang.reflect.Method,java.lang.reflect.Field相同的操作。

    import javassist.*;
    
    import java.io.IOException;
    
    public class TestJavassist {
        public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.makeClass("com.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(){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);
            // 将上述构造好的类写入myjava下文件(class文件)
            cc.writeFile("F:\\SpringBootProgram\\MyFirstWeb\\ReflectionTest\\src\\myjava");
            System.out.println("生成成功!");
        }
    }
    

    可以通过XJAD软件反编译

    占位符:0 表示this1,2...表示实际参数args表示所有参数作为一个数组
    所有方法参数的简写 move(String a,String b),move()相当于move(1,2)
    cflow 方法调用的深度r 方法返回值的类型
    _ 方法的返回值(修改方法体时不支持)class this的类型(Class),即0的类型sig 方法参数的类型(Class)数组,数组的顺序即为参数的顺序

    import javassist.*;
    
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
     * 测试javassist的API
     */
    public class TestJavassistAPI {
        // 测试类的基本用法
        public static void test1() throws NotFoundException, IOException, CannotCompileException {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("myjava.com.bean.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 test2() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("myjava.com.bean.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(\"flag\");return $1+$2;}");
            cc.addMethod(m);
            // 通过反射调用新生成的方法
            Class clazz = cc.toClass();
            // 通过无参构造器创建对象
            Object obj = clazz.newInstance();
            Method method = clazz.getDeclaredMethod("add", int.class, int.class);
            System.out.println(method.invoke(obj, 1, 2));
        }
    
        public static void test3() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("myjava.com.bean.Emp");
    
            CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[]{pool.get("java.lang.String")});
            cm.insertBefore("System.out.println($1);");
            // 在某行前插入(相对于Emp类内的行)
            cm.insertAt(29, "System.out.println(\"start\");");
            cm.insertAfter("System.out.println(\"end\");");
    
            Class clazz = cc.toClass();
            Object obj = clazz.newInstance();
            Method method = clazz.getDeclaredMethod("sayHello", String.class);
            method.invoke(obj, "kotonoha");
        }
    
        public static void test4() throws NotFoundException, CannotCompileException {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("myjava.com.bean.Emp");
    
    //        CtField f1 = CtField.make("private int empno;", cc);
            CtField f2 = new CtField(CtClass.intType, "newEmpno", cc);
            f2.setModifiers(java.lang.reflect.Modifier.PRIVATE);
            cc.addField(f2);
    
            cc.getDeclaredField("empno");// 获取指定属性
            CtMethod getNewEmpno = CtNewMethod.getter("getNewEmpno", f2);
            cc.addMethod(getNewEmpno);
            CtMethod setNewEmpno = CtNewMethod.getter("setNewEmpno", f2);
            cc.addMethod(setNewEmpno);
        }
    
        public static void test5() throws NotFoundException {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("myjava.com.bean.Emp");
    
            CtConstructor[] constructors = cc.getConstructors();
            for (CtConstructor c : constructors) {
                System.out.println(c.getLongName());
            }
        }
    
        public static void main(String[] args) throws IOException, CannotCompileException, NotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
            test4();
        }
    }
    

    相关文章

      网友评论

          本文标题:操作字节码

          本文链接:https://www.haomeiwen.com/subject/xqwahctx.html