Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。












想改善这个问题吗?更新问题,以便将其作为on-topic用于堆栈溢出。

6年前关闭。



Improve this question




出于好奇,除了cglib之外,是否有任何(稳定)开源项目用于运行时Java代码生成?我为什么要使用它们?

最佳答案

ASM java-asm

CGLIB和几乎所有其他库都建立在ASM之上,而ASM本身的作用很低。对于大多数人来说,这是一个阻止对象,因为您必须了解字节码和JVMS的一点点才能正确使用它。但是掌握ASM无疑是非常有趣的。但是请注意,尽管存在 ASM 4 guide,但在API的某些部分中,如果javadoc文档完全存在,它可能会非常简洁,但是正在对其进行改进。它紧密遵循JVM版本以支持新功能。

但是,如果您需要完全控制,ASM是您的首选武器。

该项目定期更新;在2015年5月15日发布此编辑版本5.0.4时。

Byte Buddy byte-buddy

Byte Buddy是一个相当新的库,但提供了CGLIB或Javassist提供的任何功能以及更多功能。 Byte Buddy可以完全自定义到字节码级别,并带有一种表达性强的特定于域的语言,该语言允许非常可读的代码。

  • 它支持所有JVM字节码版本,包括有关默认方法的某些操作码的Java 8语义更改。
  • ByteBuddy似乎没有遭受其他库具有
  • 的缺点的困扰
  • 高度可配置的
  • 相当快(benchmark code)
  • 类型安全流畅的API
  • 输入安全回调

  • 注释驱动(灵活)

  • 可作为代理

  • 记录良好的
  • 许多示例
  • 干净代码,〜94%的测试覆盖率
  • Android DEX支持

  • 该API的主要缺点可能是,它对于初学者来说有点冗长,但它被设计为采用代理代DSL形式的可选API;没有魔术或可疑的默认值。在处理字节码时,它可能是最安全,最合理的选择。同样,有多个示例和大量教程也不是真正的问题。

    在2015年10月,该项目收到了Oracle Duke's choice award。此时,它刚刚达到1.0.0 milestone,这是一个很大的成就。

    请注意,mockito在版本2.1.0中替换了CGLIB by Byte Buddy

    Javassist javassist

    Javassist的Javadoc比CGLIB更好。类工程API可以,但是Javassist也不是完美的。特别是,相当于CGLIB的ProxyFactoryEnhancer也有一些缺点,仅举几例:
  • 不完全支持Bridge方法(即为协变返回类型生成的方法)
  • ClassloaderProvider而是一个静态字段,然后它应用于同一类加载器中的所有实例
  • 自定义命名可能会受到欢迎(带有签名 jar 的检查)
  • 没有扩展点,几乎所有感兴趣的方法都是私有(private)的,如果我们想更改某些行为,这将很麻烦
  • 虽然Javassist支持类中的注释属性,但ProxyFactory不支持它们。

  • 在面向方面方面,可以将代码注入(inject)代理中,但是Javassist中的这种方法是有限的,并且容易出错:
  • 方面代码以纯Java字符串编写,并以操作码
  • 进行编译
  • 无类型检查
  • 没有泛型
  • no lambda
  • 没有自动装箱

  • Javassist也被认为比Cglib慢。这主要是由于其读取类文件的方法,而不是像CGLIB那样读取已加载的类的方法。而且implementation本身很难看成是公平的;如果需要更改Javassist代码,则有很多机会破坏某些东西。

    Javassist也遭受不 Activity 的困扰,他们向github circa 2013迁移似乎已被证明是有用的,因为它显示了定期的提交和来自社区的请求。

    这些限制仍然存在于3.17.1版中。该版本已被升级到3.20.0版本,但是Javassist似乎仍然对Java 8支持存在问题。

    JiteScript

    JiteScript看起来确实是为ASM精心设计DSL的新作品,它基于最新的ASM版本(4.0)。该代码看起来很干净。

    但是该项目还处于早期,因此API/行为可以更改,而且文档非常糟糕。并更新稀缺,如果不放弃的话。

    Proxetta jodd

    这是一个相当新的工具,但是它提供了迄今为止最好的人工API。它允许使用不同类型的代理,例如子类代理(cglib方法)或编织或委派。

    尽管这是相当少见的,但如果运作良好,则没有任何信息。处理字节码时有很多特殊情况需要处理。

    AspectJ aspectj

    AspectJ是用于面向方面的编程(仅)的非常强大的工具。 AspectJ通过操纵字节码来实现其目标,从而使您可以使用它来实现目标。但是,这需要在编译时进行操作。从2.54.1.x版本开始,通过代理在加载时编织Spring产品。

    CGLIB cglib

    自问这个问题以来,有关CGLIB的词汇已更新。

    CGLIB的运行速度非常快,这是它仍然存在的主要原因之一,而且CGLIB的运行情况几乎比现在(2014-2015年)的任何替代产品都要好。

    一般来说,允许在运行时重写类的库必须避免在重写相应类之前加载任何类型。因此,它们不能使用Java反射API,而Java反射API要求加载反射中使用的任何类型。相反,他们必须通过IO(这是性能破坏者)读取类文件。例如,这使得Javassist或Proxetta比Cglib慢得多,后者仅通过反射API读取方法并覆盖它们。

    但是,CGLIB不再处于积极开发中。有最新版本,但许多人认为这些更改微不足道,因为CGLIB在上一版本中引入了severe bugs,但大多数人从未更新到版本3,但实际上并没有建立起信心。 3.1版解决了3.0版的许多问题(因为4.0.3版Spring框架重新打包了version 3.1)。

    另外,CGLIB源代码的格式是poor quality,因此我们看不到新的开发人员加入CGLIB项目。对于CGLIB的活跃性印象,请参阅其mailing list

    请注意,在proposition on the guice mailing list之后,现在可以在github上使用CGLIB,以使社区能够更好地帮助该项目,它似乎正在工作(多次提交和请求,ci,更新的maven),但仍然存在大多数问题。

    目前,正在开发3.2.0版,并且他们将精力集中在Java 8上,但是到目前为止,想要Java 8支持的用户必须在构建时使用技巧。但是进展非常缓慢。

    CGLIB仍然因PermGen内存泄漏而困扰。但是其他项目可能没有经过这么多年的战斗测试。

    Compile time annotation Processing annotation-processing

    当然,这不是运行时,而是生态系统的重要组成部分,大多数代码生成用法不需要​​创建运行时。

    这从Java 5开始,Java 5带有单独的命令行工具来处理注释:apt,从Java 6开始,注释处理已集成到Java编译器中。

    有时需要您显式传递处理器,现在使用ServiceLoader方法(只需将此META-INF/services/javax.annotation.processing.Processor文件添加到jar中),编译器就可以自动检测注释处理器。

    这种代码生成方法也有缺点,它也需要大量工作并且需要Java语言(而不是字节码)的理解。该API有点麻烦,并且因为它是编译器中的插件,因此必须格外小心,以使该代码成为最有弹性和用户友好的错误消息。

    这里最大的好处是,它避免了运行时的另一个依赖关系,可以避免permgen内存泄漏。并且可以完全控制生成的代码。

    结论

    CGLIB在2002中定义了一个新的标准,可以轻松地操作字节码。当今我们拥有的许多工具和方法论(CI,覆盖率,TDD等)当时都不可用或不成熟。十多年来,CGLIB一直与时俱进;这是一个相当不错的成就。与直接操作操作码相比,它的运行速度快且具有易于使用的API。

    它定义了有关代码生成的新标准,但如今由于环境和要求已发生变化,因此不再存在,标准和目标也已发生变化。

    JVM已更改,并将在最近和将来的Java(7/8/9/10)版本(调用动态,默认方法,值类型等)中更改。 ASM会定期更新其API和内部组件以适应这些更改,但是CGLIB和其他人员尚未使用它们。

    尽管注释处理越来越受青睐,但它不像运行时生成那样灵活。

    截至2015年, Byte Buddy 虽然是新手,但为运行时生成提供了最引人注目的卖点。相当不错的更新速度,并且作者对Java字节码内部知识非常了解。

    关于java - 有cglib的替代品吗? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2261947/

    10-08 20:35