Java 动态性之字节码操作

2020/11/05

运行时操作字节码可以让我们实现如下功能:

  • 动态生成新的类

  • 动态改变某个类的结构

常见的字节码操作类库

BCEL

Byte Code Engineering Library (BCEL), 这是 Apache Software Foundation 的 Jakarta 项目的一部分。BCEL 是 Java classworking 广泛使用的一种框,它可以让您深入 JVM 汇编语言进行类操作的细节。

ASM

ASM 是一个轻量级 Java 字节码操作框架,直接涉及量到 JVM 底层的操作和指令。

CGLIB

CGLIB 是一个强大的,高性能,高质量的 Code 生成类库,基于 ASM 实现。

Javassist

Javassist 是一个开源的分析、编辑和创建 Java 字节码的类库,性能较 ASM 差,跟 CGLIB 差不多,但是使用简单。

Javassist 的 API

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

代码示例

import java.lang.reflect.Method;

import org.junit.Test;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;

public class JavassistSample {

    @Test
    public void testJavassist() throws Exception {
        final ClassPool classPool = ClassPool.getDefault();
        final CtClass ctClass = classPool.makeClass("org.javassist.A");

        // 创建属性
        final CtField ctField0 = CtField.make("private int id;", ctClass);
        final CtField ctField1 = CtField.make("private String name;", ctClass);
        ctClass.addField(ctField0);
        ctClass.addField(ctField1);

        // 创建方法
        final CtMethod ctMethod0 = CtMethod.make("public int getId() {return id;}", ctClass);
        final CtMethod ctMethod1 = CtMethod.make("public void setId(int id) {this.id = $1;}", ctClass);
        final CtMethod ctMethod2 = CtMethod.make("public String getName() {return name;}", ctClass);
        final CtMethod ctMethod3 = CtMethod.make("public void setName(String name) {this.name = $1;}", ctClass);
        ctClass.addMethod(ctMethod0);
        ctClass.addMethod(ctMethod1);
        ctClass.addMethod(ctMethod2);
        ctClass.addMethod(ctMethod3);

        // 添加构造器
        final CtConstructor ctConstructor = new CtConstructor(
                new CtClass[] { CtClass.intType, classPool.get(String.class.getName()) }, ctClass);
        ctConstructor.setBody("{this.id = $1; this.name = $2;}");
        ctClass.addConstructor(ctConstructor);

        // 生成字节码
        ctClass.writeFile("/tmp/classes");

        // 加载和执行生成的类
        final Class<?> clazz = ctClass.toClass();
        final Object object = clazz.getConstructor(int.class, String.class).newInstance(123, "abc");

        final Method getIdMethod = clazz.getMethod("getId");
        final Method getNameMethod = clazz.getMethod("getName");

        final Object id = getIdMethod.invoke(object);
        final Object name = getNameMethod.invoke(object);

        System.out.println(id);
        System.out.println(name);
    }
}

参考

https://www.cnblogs.com/dooor/p/5289326.html

Post Directory