简体   繁体   English

在Byte Buddy中缓存生成的类?

[英]Caching generated classes in Byte Buddy?

I have been using CGLIB's Enhancer for a while, but considering to switch over to Byte Buddy. 我一直在使用CGLIB的Enhancer,但考虑切换到Byte Buddy。 It's pretty basic stuff, proxy for up to a few hundred data access interfaces, created on demand. 这是非常基本的东西,可以按需创建多达数百个数据访问接口的代理。

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

CGLIB is caching the generated type to improve performance. CGLIB正在缓存生成的类型以提高性能。 What is the recommended approach with Byte Buddy? Byte Buddy的推荐方法是什么? I want to avoid any PermGen issues. 我想避免任何PermGen问题。

UPDATE: Since version 1.6, Byte Buddy provides the TypeCache class which uses soft or weak references as a blueprint for writing a cache with a custom key. 更新:从版本1.6开始,Byte Buddy提供了TypeCache类,它使用软引用或弱引用作为使用自定义键编写缓存的蓝图。 This cache contains a callback method findOrInsert which allows on demand creation of a type. 此缓存包含一个回调方法findOrInsert ,它允许按需创建类型。

With Byte Buddy, you should write your own cache because it is you who knows best about: 使用Byte Buddy,您应该编写自己的缓存,因为您最了解的是:

  • What criteria would be meaningful for caching - maybe you require two similar classes with different identity? 什么标准对于缓存有意义 - 也许你需要两个具有不同身份的类似类? Byte Buddy should not decided on that for you. Byte Buddy不应该为你做出决定。
  • What information you need to keep for maintaining the cache? 您需要保留哪些信息来维护缓存? Cglib needs to keep track of all input information what can prevent garbage collection even for classes loded with a "short-term" class loader. Cglib需要跟踪所有输入信息,即使对于使用“短期”类加载器进行编码的类,也可以防止垃圾收集。

cglib is keeping an internal cache in form of a static field with a synchronized map what bears some serious limitations. cglib将静态字段的内部缓存与同步映射保持在一起,这带来了一些严重的限制。 With this cache, it is not longer you who decides on the identity of a class when querying any Enhancer instance when using the cache. 使用此缓存,在使用缓存时查询任何 Enhancer实例时,您决定使用类的身份的时间不长。 Furthermore, the static field needs to keep track on the arguments for creating a class as for example the identity of the input callbacks which can be quite heavy. 此外,静态字段需要跟踪创建类的参数,例如输入回调的标识,这可能非常繁重。 (As a matter of fact create memory leaks by itself.) (事实上​​,创建内存泄漏本身。)

Byte Buddy wants to be an API for generating any Java class, not only for creating proxies. Byte Buddy希望成为生成任何Java类的API,而不仅仅是创建代理。 Therefore, you should know best what kind of caching makes sense. 因此,您应该最清楚哪种缓存是有意义的。 Considering your scenario where you only want to proxy an instance. 考虑您只想代理实例的场景。 Write a simple facade like: 写一个简单的外观,如:

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.
  }
}

The advantage here is that you only need to keep track of the input class as a cache reference and you can avoid synchronization if your application was single threaded. 这里的优点是您只需要将输入类作为缓存引用进行跟踪,如果应用程序是单线程的,则可以避免同步。 Also, you could define your cache to be non-static if that would fit your use case better. 此外,如果更适合您的用例,您可以将缓存定义为非静态缓存。 And even better: You could use a real cache implementation. 甚至更好:您可以使用真正的缓存实现。 This way, every library can do what it can do best. 这样,每个图书馆都可以做到最好。 Byte Buddy can create classes and the cache can, well, cache. Byte Buddy可以创建类,缓存也可以缓存。

For full disclosure, I am the author of Byte Buddy and I decided on this approach after using cglib and javassist for a while. 为了完整披露,我是Byte Buddy的作者,在使用cglib和javassist一段时间后我决定采用这种方法。 I have experienced several problems with their caches which is why I decided to not ship Byte Buddy with such a cache. 我在缓存方面遇到了一些问题,这就是为什么我决定不向Byte Buddy提供这样的缓存。 I believe it is more of a convention which was introduced by the JDK proxy's implicit caching but I do not believe that these caches are generally a good idea for the reasons described above. 我相信它更像是由JDK代理隐式缓存引入的约定,但我不相信这些缓存通常是出于上述原因的好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM