java cglib 有替代品吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2261947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are there alternatives to cglib?
提问by Mauli
Just out of curiosity, are there any (stable) open source projects for runtime java code generation other than cglib? And why should I use them?
出于好奇,除了 cglib 之外,是否有任何(稳定的)开源项目用于运行时 Java 代码生成?我为什么要使用它们?
回答by Brice
ASMjava-asm
ASM java-asm
CGLIB and almost all other libraries are built on top of ASM which itself acts on a very low level. This is a show-stopper for most people as you have to understand the byte code and a little bit of the JVMSto use it properly. But mastering ASM is most certainly very interesting. Note however that while there is a greatASM 4 guide, in some part of the API the javadoc documentation can be very concise if it is present at all, but it is being improved. It closely follows JVM versions to support new features.
CGLIB 和几乎所有其他库都建立在 ASM 之上,ASM 本身在非常低的级别上起作用。这对大多数人来说是个障碍,因为您必须了解字节码和一点点JVMS才能正确使用它。但是掌握 ASM 无疑是非常有趣的。但是请注意,虽然有一个很棒的ASM 4 指南,但在 API 的某些部分,javadoc 文档可能非常简洁,如果它存在的话,但它正在改进。它紧跟 JVM 版本以支持新功能。
However, if you need full control, ASM is your weapon of choice.
但是,如果您需要完全控制,ASM 是您的首选武器。
This project sees regular updates ; at the time of this edit version 5.0.4 was released on May 15th 2015.
该项目定期更新;在此编辑时,5.0.4 版已于 2015 年 5 月 15 日发布。
Byte Buddybyte-buddy
字节好友字节好友
Byte Buddy is a rather new library but provides any functionality that CGLIB or Javassist provides and much more. Byte Buddy can be fully customised down to the byte code level and comes with an expressive domain specific language that allows for very readable code.
Byte Buddy 是一个相当新的库,但提供了 CGLIB 或 Javassist 提供的任何功能等等。Byte Buddy 可以完全定制到字节码级别,并带有一种富有表现力的领域特定语言,允许非常可读的代码。
- It supports all JVM bytecode versions, including Java 8 semantic changes of some opcodes regarding default methods.
- ByteBuddy don't seem to suffer from the drawbacks other libraries have
- Highly configurable
- Quite fast (benchmarkcode)
- Type safe fluent API
Type safe callbacks
Javassist advices or custom instrumentation code is based on code in a plain
Stringthus type check and debugging is impossible within this code, while ByteBuddy allows to write those with pure Java hence enforces type checks and allows debugging.Annotation driven (flexible)
The user callbacks can be configured with annotations allowing to receive the wanted parameters in the callback.
Available as an agent
The nifty agent builder allows ByteBuddy to be used as a pure agent or as attaching agent. It allows different kind
- Very well documented
- Lots of example
- Clean code, ~94% test coverage
- Android DEX support
- 它支持所有 JVM 字节码版本,包括一些关于默认方法的操作码的 Java 8 语义变化。
- ByteBuddy 似乎没有受到其他库的缺点的影响
- 高度可配置
- 相当快(基准代码)
- 类型安全的流畅 API
类型安全回调
Javassist 建议或自定义检测代码基于普通代码,
String因此在此代码中不可能进行类型检查和调试,而 ByteBuddy 允许使用纯 Java 编写这些建议,因此强制执行类型检查并允许调试。注释驱动(灵活)
用户回调可以配置注释,允许在回调中接收所需的参数。
可作为代理
漂亮的代理构建器允许 ByteBuddy 用作纯代理或附加代理。它允许不同种类
- 有据可查
- 很多例子
- 干净的代码,~94% 的测试覆盖率
- 安卓 DEX 支持
The main downside perhaps, would the API is a bit verbose for a beginner but it is designed as an opt-in API shaped as a proxy generation DSL ; there's no magic or questionable defaults. When manipulating byte code it is probably the most safe and the most reasonable choice. Also with multiple examples and a big tutorial this is not a real issue.
主要的缺点可能是 API 对于初学者来说有点冗长,但它被设计为一个可选的 API,形状为代理生成 DSL;没有魔法或可疑的默认值。在操作字节码时,它可能是最安全、最合理的选择。还有多个示例和一个大教程,这不是一个真正的问题。
In October 2015 this projects received the Oracle Duke's choice award. At this times it just reached the 1.0.0 milestone, which is quite an achievement.
2015 年 10 月,该项目获得了Oracle Duke 的选择奖。这时候它刚刚达到1.0.0 里程碑,这是一个相当大的成就。
Note that mockitohas replaced CGLIB by Byte Buddyin version 2.1.0.
请注意,在 2.1.0 版本中,mockito已将CGLIB替换为 Byte Buddy。
Javassistjavassist
Javassist进行了Javassist
The javadoc of Javassist is way better than that of CGLIB. The class engineering API is OK, but Javassist is not perfect either. In particular, the ProxyFactorywhich is the equivalent of the CGLIB's Enhancersuffer from some drawbacks too, just to list a few :
Javassist 的 javadoc 比 CGLIB 的要好得多。类工程 API 还可以,但 Javassist 也不完美。特别ProxyFactory是,相当于 CGLIB 的 也Enhancer有一些缺点,仅列出一些:
- Bridge method are not fully supported (ie the one that are generated for covariant return types)
ClassloaderProvideris a static field instead, then it applies to all instances within the same classloader- Custom naming could have been welcome (with checks for signed jars)
- There is no extension point and almost all methods of interest are private, which is cumbersome if we want to change some behavior
- While Javassist offer support for annotation attributes in classes, they are not supported in
ProxyFactory.
- 不完全支持桥接方法(即为协变返回类型生成的方法)
ClassloaderProvider是一个静态字段,然后它适用于同一类加载器中的所有实例- 自定义命名可能会受到欢迎(检查签名的罐子)
- 没有扩展点,几乎所有感兴趣的方法都是私有的,如果我们想改变一些行为,这很麻烦
- 虽然 Javassist 支持类中的注释属性,但在
ProxyFactory.
On the aspect oriented side, one can inject code in a proxy, but this approach in Javassist is limited and a bit error-prone :
在面向方面的方面,可以在代理中注入代码,但是 Javassist 中的这种方法是有限的并且有点容易出错:
- aspect code is written in a plain Java String that is compiledin opcodes
- no type check
- no generics
- no lambda
- no auto-(un)boxing
- 方面代码是用在操作码中编译的纯 Java 字符串编写的
- 没有类型检查
- 没有泛型
- 没有拉姆达
- 没有自动(取消)装箱
Also Javassist is recognized to be slower than Cglib. This is mainly due to its approach of reading class files instead of reading loaded classes such as CGLIB does. And the implementationitself is hard to read to be fair ; if one requires to make changes in the Javassist code there's many chances to break something.
Javassist 也被认为比 Cglib 慢。这主要是由于它读取类文件的方法而不是读取加载的类,例如 CGLIB。并且实现本身很难公平地阅读;如果需要在 Javassist 代码中进行更改,则有很多机会破坏某些东西。
Javassist suffered from inactivity as well, their move to github circa 2013seem to have proven useful as it shows regular commits and pull requests from the community.
Javassist 也受到了不活动的影响,他们在 2013 年左右迁移到github似乎已经证明是有用的,因为它显示了来自社区的定期提交和拉取请求。
These limitations still stand in the version 3.17.1. Version has been bumped to version 3.20.0, yet it seems Javassist may still have issues with Java 8 support.
这些限制仍然存在于 3.17.1 版本中。版本已升级到 3.20.0 版,但 Javassist 似乎仍然存在对 Java 8 支持的问题。
JiteScript
JiteScript
JiteScript does seem like a new piece of nicely shaping up DSL for ASM, this is based on the latest ASM release (4.0). The code looks clean.
JiteScript 确实看起来像是为 ASM 精心打造的 DSL 的新部分,它基于最新的 ASM 版本 (4.0)。代码看起来很干净。
Butthe project is still in his early age so API / behavior can change, plus the documentation is dire. And updates scarce if not abandoned.
但该项目仍处于早期阶段,因此 API / 行为可能会发生变化,而且文档很糟糕。如果没有放弃,更新很少。
Proxettajodd
普罗克塞塔乔德
This is a rather new tool but it offers the by far best humanAPI. It allows for different types of proxies such as subclass proxies (cglib approach) or weaving or delegation.
这是一个相当新的工具,但它提供了迄今为止最好的人类API。它允许使用不同类型的代理,例如子类代理(cglib 方法)或编织或委托。
Although, this one is rather rare, no information exists if it works well. There are so many corner case to deal with when dealing with bytecode.
虽然,这个相当罕见,但如果它运作良好,则不存在任何信息。在处理字节码时,有很多极端情况需要处理。
AspectJaspectj
方面J
AspectJ is a very powerful tool for aspect-oriented programming(only). AspectJ manipulates byte code to achieve its goals such that you might be able to achieve your goals with it. However, this requires manipulation at compile-time; spring offer weaving at load time via an agent since version 2.5, 4.1.x.
AspectJ 是一个非常强大的面向方面编程的工具(仅限)。AspectJ 操纵字节码来实现它的目标,这样您就可以使用它来实现您的目标。但是,这需要在编译时进行操作;自2.5版和4.1.x版起,spring 通过代理在加载时提供编织。
CGLIBcglib
CGLIB CGLIB
A word about CGLIB that has been updated since that question has been asked.
自从提出这个问题以来,关于 CGLIB 的一句话已经更新。
CGLIB is quite fast, it is one of the main reason why it is still around, along with the fact that CGLIB worked almost better than any alternatives until now (2014-2015).
CGLIB 速度非常快,这是它仍然存在的主要原因之一,此外还有一个事实,即 CGLIB 的效果几乎比迄今为止(2014-2015 年)的任何替代方案都要好。
Generally speaking libraries that allow the rewriting of classes at run time have to avoid loading any types before the corresponding class is rewritten. Therefore, they cannot make use of the Java reflection API which requires that any type used in reflection is loaded. Instead, they have to read the class files via IO (which is a performance-breaker). This makes for example Javassist or Proxetta significantly slower than Cglib which simply reads the methods via the reflection API and overrides them.
一般来说,允许在运行时重写类的库必须避免在重写相应的类之前加载任何类型。因此,它们不能使用 Java 反射 API,该 API 要求加载反射中使用的任何类型。相反,他们必须通过 IO(这是一个性能破坏者)读取类文件。这使得 Javassist 或 Proxetta 比 Cglib 慢得多,后者只是通过反射 API 读取方法并覆盖它们。
However, CGLIB is no longer under active development. There were recent releases but those changes were seen as insignificant by many and most people did never update to version 3 since CGLIB introduced some severe bugsin the last releases what did not really build up confidence.Version 3.1 fixed a lot of the woes of version 3.0 (since version 4.0.3 Spring framework repackages version 3.1).
但是,CGLIB 不再处于积极开发状态。有最近的版本,但许多人认为这些变化微不足道,大多数人从未更新到版本 3,因为 CGLIB在上一个版本中引入了一些严重的错误,这些错误并没有真正建立信心。3.1 版修复了 3.0 版的很多问题(因为 4.0.3 版 Spring 框架重新打包了3.1 版)。
Also, the CGLIB source code is of rather poor qualitysuch that we do not see new developers joining the CGLIB project. For an impression of CGLIB's activeness, see their mailing list.
此外,CGLIB 源代码的质量相当差,以至于我们看不到新的开发人员加入 CGLIB 项目。要了解 CGLIB 的活跃度,请参阅他们的邮件列表。
Note that following a proposition on the guice mailing list, CGLIB is now available on githubto enable the community to better help the project, it appears to be working (multiple commits and pull requests, ci, updated maven), yet most concerns still remain.
请注意,根据 guice 邮件列表上的提议,CGLIB 现在可在github上使用,以使社区能够更好地帮助该项目,它似乎正在运行(多次提交和拉取请求、ci、更新的 maven),但大多数问题仍然存在.
At this time there are working on version 3.2.0, and they are focusing effort on Java 8, but so far users that want that java 8 support have to use tricks at build time. But progress is very slow.
目前正在开发 3.2.0 版本,并且他们专注于 Java 8,但到目前为止,想要 Java 8 支持的用户必须在构建时使用技巧。但进展非常缓慢。
And CGLIB is still known to be plagued for PermGen memory leak. But other projects may not have been battle tested for so many years.
众所周知,CGLIB 仍然受到 PermGen 内存泄漏的困扰。但其他项目可能没有经过这么多年的实战考验。
Compile time annotation Processingannotation-processing
编译时注解处理注解-处理
This one is not runtime of course, but is an important part of the ecosystem, and most code generation usage don't need runtime creation.
这当然不是运行时,而是生态系统的重要组成部分,大多数代码生成使用不需要运行时创建。
This started with Java 5 that came with the separate command line tool to process annotations : apt, and starting from Java 6 annotation processing is integrated into the Java compiler.
这从 Java 5 开始,它带有单独的命令行工具来处理注释 : apt,从 Java 6 开始,注释处理被集成到 Java 编译器中。
At some time you were required to explicitly pass the processor, now with the ServiceLoaderapproach (just add this file META-INF/services/javax.annotation.processing.Processorto the jar) the compiler can detect automatically the annotation processor.
有时您需要显式传递处理器,现在使用这种ServiceLoader方法(只需将此文件添加META-INF/services/javax.annotation.processing.Processor到 jar 中),编译器可以自动检测注释处理器。
This approach at code generation has drawbacks too it require a lot of work and understanding of the Java language not bytecode. This API is a bit cumbersome, and as one is plugin in the compiler one must take extreme care to make this code the most resilient and user friendly error message.
这种代码生成方法也有缺点,它需要大量的工作和对 Java 语言的理解,而不是字节码。这个 API 有点麻烦,因为它是编译器中的插件,所以必须非常小心,使这段代码成为最具弹性和用户友好的错误消息。
The biggest advantage here is that it avoids another dependency at runtime, you may avoid permgen memory leak. And one has full control on the generated code.
这里最大的优点是它避免了运行时的另一个依赖,你可以避免永久内存泄漏。并且可以完全控制生成的代码。
Conclusion
结论
In 2002CGLIB defined a new standard to manipulate bytecode with ease. Many tools and methodology (CI, coverage, TDD, etc.) we have nowadays were not available or not mature at that time. CGLIB managed to be relevant for more than a decade ; that's a pretty decent achievement. It was fast and with an easy API to use than manipulating opcodes directly.
在2002年CGLIB定义了新的标准来操纵字节码轻松。我们现在拥有的许多工具和方法(CI、覆盖率、TDD 等)当时都不可用或不成熟。CGLIB 成功地保持了相关性超过十年;这是一个相当不错的成就。与直接操作操作码相比,它速度快且 API 易于使用。
It defined new standard regarding code generation but nowadays it isn't anymore because environment and requirements have changed, so have the standards and goals.
它定义了关于代码生成的新标准,但现在它不再是因为环境和要求已经改变,所以标准和目标也改变了。
The JVM changed and will change in recent and future Java (7/8/9/10) versions (invokedynamic, default methods, value types, etc). ASM upgraded his API and internals regularly to follow these changes but CGLIB and others have yet to use them.
JVM 在最近和未来的 Java (7/8/9/10) 版本(invokedynamic、默认方法、值类型等)中发生了变化,并将发生变化。ASM 定期升级他的 API 和内部组件以遵循这些更改,但 CGLIB 和其他人尚未使用它们。
While annotation processing is getting traction, it is not as flexible as runtime generation.
虽然注释处理越来越受欢迎,但它不如运行时生成灵活。
As of 2015, Byte Buddy— while rather new on the scene— offer the most compelling sellingpoints for runtime generation. A decent update rate, and the author has an intimate knowledge of the Java byte code internals.
截至2015年,字节巴迪-而相当新的现场-提供了最有说服力的卖点运行时产生点。不错的更新率,作者对 Java 字节码内部结构有深入了解。
回答by Bozho
If you need to make proxies, take a look at commons-proxy- it uses both CGLIB and Javassit.
如果您需要制作代理,请查看commons-proxy- 它同时使用 CGLIB 和 Javassit。
回答by CurtainDog
I prefer raw ASM, which I believe is used by cglib anyway. It's low level, but the documentation is brilliant, and once you get used to it you'll be flying.
我更喜欢 raw ASM,我相信 cglib 无论如何都会使用它。它的级别很低,但文档很棒,一旦你习惯了它,你就会飞起来。
To answer your second question, you should use code generation when your reflection and dynamic proxies are beginning to feel a bit cobbled together and you need a rock solid solution. In the past I've even added a code generation step into the build process in Eclipse, effectively giving me compile time reporting of anything and everything.
要回答您的第二个问题,当您的反射和动态代理开始感觉有点拼凑在一起并且您需要一个坚如磐石的解决方案时,您应该使用代码生成。在过去,我什至在 Eclipse 的构建过程中添加了一个代码生成步骤,有效地让我在编译时报告任何事情。
回答by FoxyBOA
I think it's more sense to use Javassistinstead of cglib. E.g. javasist perfectly works with signed jars unlike cglib. Besides, such grand as Hibernate project decided to stop using cglib in favor of Javassist.
我认为使用Javassist而不是 cglib更有意义。例如,与 cglib 不同,javasist 可以完美地与签名的 jar 一起使用。此外,像 Hibernate 这样的伟大项目决定停止使用 cglib,转而使用 Javassist。
回答by jbaliuka
CGLIB was designed and implemented more than ten years ago in AOP and ORM era. Currently I see no reasons to use it and I do not maintain this library anymore (except bug fixes for my legacy applications ). Actually all of CGLIB use cases I have ever saw are anti patterns in modern programming. It should be trivial to implement the same functionality via any JVM scripting language e.g. groovy.
CGLIB 是十多年前在 AOP 和 ORM 时代设计和实现的。目前我看不到使用它的理由,我不再维护这个库(除了我的遗留应用程序的错误修复)。实际上,我见过的所有 CGLIB 用例都是现代编程中的反模式。通过任何 JVM 脚本语言(例如 groovy)实现相同的功能应该是微不足道的。

