我自己写了一个javaagent,用ASM动态地插装java类(我没有使用ASM的COMPUTE_MAXS或COMPUTE_FRAMES,我自己手工做的)。实际上,我只是尝试对非构造函数方法使用一个很大的try-catch块来捕获未捕获的异常或错误,并记录此类事件(我的代码实际上是this question代码的修订版)。
但是,当我尝试在一个开源项目joda-time的测试过程中使用我的javaagent时,出现了以下错误:
org.apache.maven.surefire.testset.TestSetFailedException: org.joda.time.TestAllPackages
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:116)
at org.apache.maven.surefire.junit.JUnit3Provider.executeTestSet(JUnit3Provider.java:140)
at org.apache.maven.surefire.junit.JUnit3Provider.invoke(JUnit3Provider.java:113)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:379)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:340)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:125)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:413)
Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "org/joda/time/DateTimeZone"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.joda.time.TestChronology.<clinit>(TestChronology.java:47)
at org.joda.time.TestAll.suite(TestAll.java:37)
at org.joda.time.TestAllPackages.suite(TestAllPackages.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.createInstanceFromSuiteMethod(JUnit3Reflector.java:157)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.constructTestObject(JUnit3Reflector.java:124)
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:75)
... 6 more据我所知,每次sun/misc/Launcher$AppClassLoader试图装入一个类时,都会进入ClassFileTransformer的transform方法。在我修改类并返回修改后的字节数组后,类最终被装入。因此,每个类应该只加载一次。
我进一步尝试打印出类名和在transform方法开始时加载它的加载器,我发现org/joda/time/DateTimeZone只出现一次,这与我的理解是一致的。
所以现在唯一与我的理解不一致的是错误。为什么sun/misc/Launcher$AppClassLoader attempted duplicate class definition和我的经纪人在一起?当我删除我的-javaagent选项时,一切都变得如此迅速。
发布于 2021-10-14 06:59:20
为了计算帧,ASM需要在跳转指令的目标处找到几个类的公共超类。为此,ASM加载类以浏览其层次结构。如果您以这种方式加载一个类,而它在第一次加载时也被检测,那么该类将在检测后加载,您将以此错误结束。
为了避免这种情况,您可以覆盖ASM的ClassWriter的getCommonSuperClass方法。您需要解析传递给方法的这些类的类文件,而不是加载它们。如果你想要这样的现成实现,你可以使用Byte Buddy,它公开了ASM,并以这种方式解析了它的ClassWriter。
https://stackoverflow.com/questions/69563714
复制相似问题