gpt4 book ai didi

java - 在调用另一个方法之前注入(inject)一个 Java 方法

转载 作者:搜寻专家 更新时间:2023-10-30 21:33:56 24 4
gpt4 key购买 nike

我正在使用 ASM 并想重写如下内容:

someMethod().targetMethod(args...)

到:

someMethod().injectedMethod(arg).targetMethod(args...)

问题是我不知道之前的方法是什么,我只知道目标方法(所以找到 someMethod() 并在之后注入(inject)不是一个选项)。

我还有许多版本的目标方法,我希望它使用不同的参数集。

使用 ASM 我可以很容易地找到目标方法调用,但不幸的是此时的操作数堆栈是:

[ argN, ..., arg1, instance, ... ]

虽然我可以计算出实例的深度,但我没有可以注入(inject)的字节码来读取它。我知道您可以使用 dup 命令的技巧对最多 4 个参数执行此操作,但我需要一个通用的解决方案。

我可以添加一堆局部变量并从堆栈中复制所有内容,复制指向的实例并将所有内容放回原处,但这是我真的不想要的运行时效率低下。

我认为可行的是,如果我可以跟踪哪些指令负责将实例指针放入堆栈,然后我可以在那里而不是在目标方法调用处注入(inject)我的方法调用。然而,我没有找到任何帮助我做到这一点的运气。

我知道像 AspectJ 这样的东西允许这样做,但是在加载很多类时必须这样做,而 AspectJ 太慢了。

谁能指出构建在 ASM 之上的分析工具可以让我这样做,或者谁能想到一种更好的方法来在另一个方法调用之前注入(inject)一个方法调用?

最佳答案

如果我正确理解你的问题,我已经达到了你想要做的,但方式不同。

使用 ASM 事件驱动字节码修改,我首先将 someMethod( arg, arg, arg ) 重命名为 copyOf_someMethod( arg, arg, arg )。然后我创建了一个名为 someMethod( arg, arg, arg ) 的新方法,该方法进行了一些处理,然后调用了 copyOf_someMethod( arg, arg, arg )。

我在我实现的 ClassVisitor 的 visitMethod(..) 方法中做了方法重命名:

MethodVisitor methodVisitor =
super.visitMethod(
methodAccess, "copyOf_" + methodName, methodDesc,
methodSignature, methodExceptions );

return methodVisitor;

在 visitMethod(..) 中,我还将所有方法签名详细信息存储在类变量中,准备在 visitEnd() 方法中使用。

我实际上将方法详细信息存储在 MethodDetail 对象中并将其放入队列中:

private Queue<MethodDetail> methodDetails = new LinkedList<MethodDetail>();

我使用我实现的 ClassVisitor 的 visitEnd() 方法创建了 someMethod( arg, arg, arg ) 的新实现。我使用 ASMFier 生成代码以放入 visitEnd() 方法中。该实现使用了我之前存储在 visitMethod(..) 中的详细信息。新的实现做了一些处理,然后调用了 copyOf_someMethod()。在 visitEnd() 方法中,我弹出了队列的所有 MethodDetail 以及我之前由 ASMFier 生成的每个 MethodDetail 调用的 ASM 代码。

使用这种设计,我为一个方法创建了一个代理,该方法进行一些处理,然后调用原始方法。请注意,原始方法已重命名为 copyOf_someMethod(..)。另请注意,我为充当代理的原始方法提供了新的实现。

为了支持多个参数,我使用 ASMFier 为 1 个参数、2 个参数、3 个参数等生成不同的代码。我最多支持 7 个参数,如果被代理的方法有超过 7 个参数,我会抛出一个不受支持的异常。在 visitEnd(..) 方法中,我调用了不同的代码(由 ASMFier 生成),具体取决于原始方法有多少方法参数。

我使用了 javaagent 来拦截类加载并修改字节。

由于我是 ASM 的新手,也许我没有正确理解您的问题 - 但是,如果您的问题是关于创建一个执行某些处理然后调用原始方法的代理,那么我的解决方案就可以了。似乎并不慢。其方法被代理的类的类加载时间并不比没有字节码修改慢多少。引入代码的运行速度并不慢,ASMFier生成的ASM代码显得非常快。

干杯

关于java - 在调用另一个方法之前注入(inject)一个 Java 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13933960/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com