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

时间:2015-10-09 12:44:28

标签: java classloader instrumentation javassist javaagents

我在运行由代理检测的 java 8 应用程序时调查一个奇怪的异常,该应用程序使用 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()导致了这一点。调用此方法时必须有一些(Classloading?)副作用 已经重现该错误的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;
  }


正如您所看到的,我总是返回班级的未触及的byte[]表示,我没有修改任何类。
删除时使用pool.makeClass()的行,应用程序正常运行。

问题:
你能否告诉我这里有什么问题以及makeClass()引起的副作用是什么?

2 个答案:

答案 0 :(得分:1)

执行加载时转换时,一旦安装了转换器,就会为所有尝试加载的类调用transform方法。这包括Javassist本身所需的类,如果它们尚未加载。因此,如果不排除这些类,则会创建循环依赖项。当您尝试使用仍在运行变换器的类(在同一线程内)时,JVM似乎会对NoClassDefFoundError作出反应。

作为旁注,如果您不更改类,我建议返回null告诉JVM您没有更改任何内容。否则,JVM不知道您是否已写入数组并且必须重新解析数据(或将它们与原始字节进行比较以发现它们未被更改)。这只是一个性能问题。

答案 1 :(得分:0)

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

Javasisst是否与Java 8完全兼容?