Javassist:ClassPool.makeClass() 的副作用?

Javassist: Side effects of ClassPool.makeClass()?

我正在调查一个奇怪的 异常 当 运行 一个 java 8 应用程序被 agent 使用 Javassist

Exception in thread "main" java.lang.BootstrapMethodError: java.lang.NoClassDefFoundError: Could not initialize class java.lang.invoke.CallSite
        at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
        at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
        ... 7 more


在进一步调查中,似乎是 Javassist 的 ClassPool.makeClass() 导致了这一点。调用此方法时肯定有一些(类加载?)副作用
我的 ClassFileTransformer 的简约版本已经重现了这个错误:

  public byte[] transform(ClassLoader loader, String className,
      Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
      byte[] classfileBuffer) throws IllegalClassFormatException
  {
    ClassPool pool = ClassPool.getDefault();
    try
    {
      CtClass makeClass = pool.makeClass(new java.io.ByteArrayInputStream(
          classfileBuffer));
    }
    catch (IOException | RuntimeException e)
    {
      e.printStackTrace();
    }

    return classfileBuffer;
  }


如您所见,我总是返回 class 的未修改 byte[] 表示,我没有修改任何 classes。
删除带有 pool.makeClass() 的行时,应用程序运行正常。

问题:
你能告诉我这里出了什么问题吗?makeClass() 的副作用是什么导致的?

当我看到 CallSite 时,它看起来像是 Java 8 编译器完成的 lambda 魔术,以支持将 lambda 调用站点引导至 invokedynamic。有关详细信息,请参阅 LambdaMetaFactory 的 Java 文档。

Javasisst 是否与 Java8 完全兼容?

当您执行加载时转换时,您的 transform 方法会在安装转换器后为所有试图加载的 class 调用。这包括 Javassist 本身所需的 classes,如果它们尚未加载的话。所以如果你不排除这些 classes,你就会创建一个循环依赖。当您尝试使用 class 时,JVM 似乎会对 NoClassDefFoundError 做出反应,而转换器仍然是 运行(在同一线程中)。

附带说明一下,如果您不更改 class,我建议返回 null 以告诉 JVM 您没有更改任何内容。否则,JVM 不知道你是否已经写入数组,必须重新解析数据(或将它们与原始字节进行比较,以发现它们没有改变)。这只是一个性能问题。