gpt4 book ai didi

java-bytecode-asm - 动态Java字节码操作框架比较

转载 作者:行者123 更新时间:2023-12-03 09:23:05 25 4
gpt4 key购买 nike

有一些框架可用于动态字节码生成、操作和编织(BCEL、CGLIB、javassist、ASM、MPS)。我想了解它们,但由于我没有太多时间了解所有这些的所有细节,我想看一种比较图表,说明一个与其他的优缺点以及对它们的解释为什么。

在这里,我发现很多问题都在问类似的问题,答案通常是“你可以使用 cglib 或 ASM”,或者“javassist 比 cglib 更好”,或者“BCEL 老了,快死了”或“ASM 是最好的,因为它给出了 X 和 Y”。这些答案很有用,但并没有完全回答我想要的范围内的问题,更深入地比较它们并给出每个的优缺点。

最佳答案

字节码库分析

正如我从你在这里得到的答案和你所看到的问题中的答案中可以看出的那样,这些答案并没有以你所说的明确方式正式解决这个问题。您要求进行比较,同时这些答案根据您的目标(例如,您需要了解字节码吗?[y/n])含糊地说明了人们可能想要什么,或者太狭隘。

这个答案是对每个字节码框架的简短分析,并在最后提供了快速比较。

Javassist

  • 微小(javassist.jar (3.21.0) 为~707KB/javassist-rel_3_22_0_cr1.zip 为~1.5MB)
  • 高(/低)级
  • 直截了当
  • 功能完备
  • 需要最少到没有类文件格式知识
  • 需要中等 Java 指令集知识
  • 最小的学习努力
  • 在单行/多行编译和插入字节码方法中有一些怪癖

  • 我个人更喜欢 Javassist,因为您可以快速使用它并使用它构建和操作类。 tutorial 简单易懂。 jar 文件只有 707KB,所以它很好且可移植;使其适用于独立应用程序。

    ASM
  • 大(asm-6.0_ALPHA-bin.zip ~2.9MB/asm-svn-latest.tar.gz (10/15/2016) ~41MB)
  • 低(/高)级
  • 综合
  • 功能完备
  • 推荐精通class文件格式的知识
  • 需要精通 Java 指令集
  • 中等学习努力(有点复杂)

  • ObjectWeb 的 ASM 是一个非常全面的库,它没有与构建、生成和加载类相关的任何内容。事实上,它甚至有带有预定义分析器的类分析工具。据说它是字节码操作的行业标准。这也是我避开它的原因。

    当我看到 ASM 的例子时,它似乎是一个繁琐的任务,修改或加载一个类需要多少行。甚至某些方法的某些参数似乎有点神秘,而且对于 Java 来说是不合适的。像 ACC_PUBLIC 这样的东西,以及到处都是 null 的大量方法调用,老实说,它看起来更适合像 C 这样的低级语言。为什么不简单地传递一个像“public”这样的字符串文字,或者一个枚举 0x2518122314133?它更友好且易于使用。不过,这是我的看法。

    作为引用,这里是 ASM (4.0) 教程: https://www.javacodegeeks.com/2012/02/manipulating-java-class-files-with-asm.html

    BCEL
  • 小(bcel-6.0-bin.zip 为 7.3MB/bcel-6.0-src.zip 为 1.4MB)
  • 低级
  • 足够
  • 完成工作
  • 需要精通 Java 指令集
  • 简单易学

  • 据我所知,这个库是你的基本类库,它可以让你做你需要做的一切——如果你能抽出几个月或几年的时间。

    这是一个 BCEL 教程,它真正说明了这一点: http://www.geekyarticles.com/2011/08/manipulating-java-class-files-with-bcel.html?m=1

    cglib
  • 非常小( cglib-3.2.5.jar 是 295KB/source code )
  • 取决于 ASM
  • 高级
  • 特征完整(字节码生成)
  • 几乎不需要 Java 字节码知识
  • 简单易学
  • 深奥的图书馆

  • 尽管您可以从类中读取信息,并且可以转换类,但该库似乎是为代理量身定制的。 tutorial 全是关于代理的 bean,它甚至提到它被“数据访问框架用来生成动态代理对象和拦截字段访问”。尽管如此,我认为没有理由不能将它用于更简单的字节码操作目的而不是代理。

    ByteBuddy
  • 小垃圾箱/“巨大” src(相比之下)(byte-buddy-dep-1.8.12.jar 是 ~2.72 MB/1.8.12 (zip) 是 124.534 MB(精确))0x214293
  • 取决于 ASM
  • 高级
  • 功能完备
  • 就个人而言,服务模式类(ByteBuddy.class)的特殊名称
  • 需要很少或不需要 Java 字节码知识
  • 简单易学

  • 长话短说,BCEL 缺乏的地方,ByteBuddy 很丰富。它使用服务设计模式使用名为 ByteBuddy 的主要类。您创建了一个 ByteBuddy 的新实例,这表示您要修改的类。完成修改后,您可以使用 Modifier.PUBLIC 创建一个 DynamicType

    在他们的网站上有完整的 API 文档教程。目的似乎是进行相当高级别的修改。说到方法,官方教程或任何 3rd 方教程中似乎没有任何关于从头开始创建方法的内容,除了委托(delegate)方法( EDITME ,如果你知道在哪里解释)。

    他们的教程可以在 here on their website 找到。一些示例可以在 here 中找到。

    Java Class Assistant (jCLA)

    我正在构建自己的字节码库,将被称为 Java Class Assistant,或简称 jCLA,因为我正在从事另一个项目,并且因为 Javassist 的上述怪癖,但我不会将其发布到 GitHub,直到它已经完成,但该项目目前可以在 GitHub 上浏览并提供反馈,因为它目前处于 alpha 阶段,但仍然可以用作基本类库(目前正在开发编译器;如果可以,请帮助我!它将早点发布!)。

    它将非常简单,具有在 JAR 文件中读取和写入类文件的能力,以及在源代码和类文件之间编译和反编译字节码的能力。

    整体使用模式使得使用 jCLA 变得相当容易,尽管它可能需要一些时间来适应并且在类修改的方法和方法参数风格方面与 ByteBuddy 显然非常相似:
    import jcla.ClassPool;
    import jcla.ClassBuilder;
    import jcla.ClassDefinition;
    import jcla.MethodBuilder;
    import jcla.FieldBuilder;

    import jcla.jar.JavaArchive;

    import jcla.classfile.ClassFile;

    import jcla.io.ClassFileOutputStream;

    public class JCLADemo {

    public static void main(String... args) {
    // get the class pool for this JVM instance
    ClassPool classes = ClassPool.getLocal();
    // get a class that is loaded in the JVM
    ClassDefinition classDefinition = classes.get("my.package.MyNumberPrinter");
    // create a class builder to modify the class
    ClassBuilder clMyNumberPrinter= new ClassBuilder(classDefinition);

    // create a new method with name printNumber
    MethodBuilder printNumber = new MethodBuilder("printNumber");
    // add access modifiers (use modifiers() for convenience)
    printNumber.modifier(Modifier.PUBLIC);
    // set return type (void)
    printNumber.returns("void");
    // add a parameter (use parameters() for convenience)
    printNumber.parameter("int", "number");
    // set the body of the method (compiled to bytecode)
    // use body(byte[]) or insert(byte[]) for bytecode
    // insert(String) also compiles to bytecode
    printNumber.body("System.out.println(\"the number is: \" + number\");");
    // add the method to the class
    // you can use method(MethodDefinition) or method(MethodBuilder)
    clMyNumberPrinter.method(printNumber.build());

    // add a field to the class
    FieldBuilder HELLO = new FieldBuilder("HELLO");
    // set the modifiers for hello; convenience method example
    HELLO.modifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL);
    // set the type of this field
    HELLO.type("java.lang.String");
    // set the actual value of this field
    // this overloaded method expects a VariableInitializer production
    HELLO.value("\"Hello from \" + getClass().getSimpleName() + \"!\"");

    // add the field to the class (same overloads as clMyNumberPrinter.method())
    clMyNumberPrinter.field(HELLO.build());

    // redefine
    classDefinition = clMyNumberPrinter.build();
    // update the class definition in the JVM's ClassPool
    // (this updates the actual JVM's loaded class)
    classes.update(classDefinition);

    // write to disk
    JavaArchive archive = new JavaArchive("myjar.jar");
    ClassFile classFile = new ClassFile(classDefinition);
    ClassFileOutputStream stream = new ClassFileOutputStream(archive);

    try {
    stream.write(classFile);
    } catch(IOException e) {
    // print to System.out
    } finally {
    stream.close();
    }
    }

    }

    ( VariableInitializer production specification for your convenience. )

    从上面的代码片段中可以看出,每个 make() 都是不可变的。这使得 jCLA 更加安全、线程安全、网络安全且易于使用。该系统主要围绕 ClassDefinition 作为以高级方式查询类信息的首选对象,并且系统的构建方式是 ClassDefinition 与目标类型(如 ClassBuilder 和 ClassFile)相互转换。

    jCLA 对类数据使用分层系统。在底部,您有不可变的 ClassDefinition :类文件的结构或软件表示。然后你有不可变的 ClassFile s,它们从 ClassFiles 转换为不那么神秘、更易于管理和对从类中修改或读取数据的程序员有用的东西,并且与通过 ClassDefinition 访问的信息相当。最后,你有可变的 java.lang.Class s。 ClassBuilder 是修改或创建类的方式。它允许您从当前状态直接从构建器创建 ClassBuilder。没有必要为每个类创建一个新的构建器,因为 ClassDefinition 方法将清除变量。

    (该库的分析将在准备发布后立即提供。)

    但在那之前,截至今天:
  • 小(源代码:227.704 KB 准确,2018 年 6 月 2 日)
  • 自给自足(除了 Java 附带的库之外没有依赖项)
  • 高级
  • 无需了解 Java 字节码或类文件(对于 1 层 API,例如 ClassBuilder、ClassDefinition 等)
  • 易于学习(如果来自 ByteBuddy 则更容易)

  • 不过,我仍然建议学习 Java 字节码。这将使调试更容易。

    比较

    综合所有这些分析(目前不包括jCLA),最广泛的框架是ASM,最容易使用的是Javassist,最基本的实现是BCEL,字节码生成和代理的最高级别是cglib。

    ByteBuddy 值得自己解释。它像 Javassist 一样易于使用,但似乎缺少一些使 Javassist 变得出色的功能,例如从头开始创建方法,因此显然您需要使用 ASM。如果你需要对类做一些轻量级的修改,ByteBuddy 是不二之选,但对于更高级的类修改同时保持高抽象级别,Javassist 是更好的选择。

    注意:如果我错过了图书馆,请编辑此答案或在评论中提及。

    关于java-bytecode-asm - 动态Java字节码操作框架比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9167436/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com