java - 在 Byte Buddy 中缓存生成的类?

标签 java code-generation bytecode proxy-classes byte-buddy

我已经使用 CGLIB 的 Enhancer 一段时间了,但正在考虑切换到 Byte Buddy。这是非常基本的东西,代理多达数百个数据访问接口(interface),按需创建。

Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(...);
enhancer.setSuperclass(...);
enhancer.setInterfaces(...);
enhancer.setCallback(...);
enhancer.create();

CGLIB 正在缓存生成的类型以提高性能。 Byte Buddy 推荐的方法是什么?我想避免任何 PermGen 问题。

最佳答案

更新:从 1.6 版开始,Byte Buddy 提供了 TypeCache 类,该类使用软引用或弱引用作为蓝图来编写带有自定义键的缓存。此缓存包含回调方法 findOrInsert,允许按需创建类型。

使用 Byte Buddy,您应该编写自己的缓存,因为您最了解:

  • 哪些标准对缓存有意义 - 也许您需要两个具有不同身份的相似类?字节好友不应该为你做决定。
  • 您需要保留哪些信息来维护缓存? Cglib 需要跟踪所有可以防止垃圾回收的输入信息,即使对于使用“短期”类加载器加载的类也是如此。

cglib 以带有同步映射的静态字段形式保留内部缓存,但存在一些严重的局限性。有了这个缓存,在使用缓存查询任何 Enhancer 实例时,不再由您来决定类的身份。此外,静态字段需要跟踪创建类的参数,例如输入回调的标识,这可能非常繁重。 (实际上是自己造成内存泄漏。)

Byte Buddy 希望成为一个用于生成任何 Java 类的 API,而不仅仅是用于创建代理。因此,您应该最清楚哪种缓存是有意义的。考虑您只想代理一个实例的场景。编写一个简单的门面,例如:

class MyProxyGenerator {
  static Map<Class<?>, Class<?>> proxies = new HashMap<>();
  public Class<?> makeProxy(Class<?> type) {
    if(proxies.contains(type)) {
      return proxies.get(type);
    } else {
      Class<?> proxy = doMakeProxy(type);
      proxies.put(type, proxy);
      return proxy;
    }
  }
  private Class<?> doMakeProxy(Class<?> type) {
    // use Byte Buddy here.
  }
}

这里的优点是你只需要跟踪输入类作为缓存引用,如果你的应用程序是单线程的,你可以避免同步。此外,如果这样更适合您的用例,您可以将缓存定义为非静态的。甚至更好:您可以使用真正的缓存实现。这样,每个图书馆都可以做它最擅长的事情。 Byte Buddy 可以创建类,缓存也可以缓存。

为了全面披露,我是 Byte Buddy 的作者,在使用 cglib 和 javassist 一段时间后我决定采用这种方法。我在他们的缓存中遇到了几个问题,这就是为什么我决定不为 Byte Buddy 提供这样的缓存。我相信这更像是 JDK 代理的隐式缓存引入的约定,但由于上述原因,我不认为这些缓存通常是个好主意。

关于java - 在 Byte Buddy 中缓存生成的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23732236/

相关文章:

java - 如何在 Spring Boot 中将 S3 对象转换为资源?

java - 如何创建滚动背景?

python - Python 中经过评估/动态生成的函数的源代码

java - 有什么方法可以知道执行字节代码时 JVM 的速度吗?

java - 对生产中的一段 Java 代码进行计时。

java - 如何在 Java 中将 HMAC key 指定为十六进制

.Net SvcUtil : attributes must be optional

version-control - 混合 WaveMaker/Java 项目 - 如何做?

jvm - 创建一个简单的领域特定语言

c++ - 使用 C++ 从 .swf 中提取变量