美文网首页
操作字节码

操作字节码

作者: 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();
    }
}

相关文章

  • JavaAgent 与 动态代理

    ASM, CGlib, Java Proxy, Javassist都是可以操作字节码,但是这些操作字节码都需要等到...

  • 43 AOP(面向切面编程)-ASM-1

    AspectJ 非常强大,但是它也只能实现 50% 的字节码操作场景,如果想要实现 100% 的字节码操作场景,那...

  • 深入探索编译插桩技术ASM

    AspectJ 非常强大,但是它也只能实现 50% 的字节码操作场景,如果想要实现 100% 的字节码操作场景,那...

  • 史上最全的ASM原理解析与应用

    ASM简介 ASM是一个操作Java字节码类库,其操作的对象是字节码数据,处理字节码方式是“拆分-修改-合并”将....

  • Java虚拟机知识点【字节码】

    字节码指令   Java虚拟机的字节码指令由一个字节长度,代表着某种特定操作含义的操作码以及跟随其后的零至多个代表...

  • 操作字节码

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

  • 【JAVA】JAVA中的小知识(补充中...)

    Java文件经过JVM编译成字节码文件,即.class文件,将字节码文件在不同的操作系统中运行时,操作系统再将字节...

  • Java虚拟机-字节码指令

    1 字节码指令 Java字节码指令的执行离不开操作数栈,局部变量表,和常量池。 2 常量池 对于字节码指定来说,常...

  • Java的动态机制---字节码操作

    字节码 1 动态生成新的类 动态改变类的结构 2 字节码操作库 BCEL ASM CGLIB Javassist ...

  • Java 动态特性二:字节码操作

    java本身动态性的两种实现方式:反射和字节码操作 字节码操作:可以实现动态生成一个类(.class文件)和动态的...

网友评论

      本文标题:操作字节码

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