我一直在尝试使用 Java 代理通过 ASM 应用字节码转换。
我使用 premain
方法实现了一个 Agent,向 Instrumentation 添加了一个转换器。
我在 .jar list 中添加了“Premain-Class”行
Premain-Class: <MyAgentPath>
然后我尝试使用代理运行该应用程序。
我有一个问题:我的转换器修改了一些方法调用,所以如果不是所有涉及的类都被修改了,它就无法工作。还有一些没有被修改的类,比如“org.apache.commons.math3.util.FastMath”。
当然,我得到了错误:
java.lang.NoSuchMethodError: org.apache.commons.math3.util.FastMath.floor<new_descriptor>
我检查了很多帖子,说它可能是引导加载程序,它不知道此类的路径,因此我尝试使用不同的方式添加它:
Boot-Class-Path: <...>/commons-math3<...>.jar
inst.appendToBootstrapClassLoaderSearch("<...>/commons-math3<...>.jar");
-Xbootclasspath/a:<...>/commons-math3<...>.jar
这一切都没有改变任何事情。
我还使用了 Instrumentation 类方法
getAllLoadedClasses()
来查看加载了哪些类,以及加载了应用程序进程中涉及的所有类,包括 FastMath。for(Class<?> clazz : MyAgent.getInstInstance().getAllLoadedClasses()){
buffWrite.write(clazz.getName());
由于“FastMath”类给出了一个错误,并且 Bootstrap 加载器应该有它的路径,我尝试向同一包中其他类的方法添加一些方法调用。似乎问题并未出现在包的每个类中。
例如:
MathUtils
被转换并调用修改后的方法 checkFinite(D)V
-> checkFinite<new_descriptor>
。所以我猜这个问题与提供给引导加载程序的路径无关。
如果您对正在发生的事情有一些想法,我会很高兴听到的!
最佳答案
NoSuchMethodError
很可能不是由未向引导类加载器添加内容引起的。这可能是一个问题的唯一机会是,如果突然有两个这样的 jar 可用,一个装有仪器,另一个没有。
如果您将方法 checkFinite(D)V
调用更改为另一个方法 checkFinite<new_descriptor>
,那么您需要确保使用 FastMath.floor
的任何类都将描述符更新为该方法。这意味着您需要遍历每个类的每个方法以查找 ASM 的 visitMethodIns
调用。好像你错过了一些。由于您正在更改 FastMath
类的布局,因此 必须在第一次加载时对其进行 检测,并且 不能重新定义它 。
Java 内部类不知道 FastMath
,因为这是第三方依赖项。因此,应该可以检测来自您的代理的任何调用。在我看来,您正在过早地加载 FastMath
。
关于Java 代理 : transform() not applied on all classes,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34285862/