我可以使用 ByteBuddy 检测传出方法/构造函数调用吗?
Posted
技术标签:
【中文标题】我可以使用 ByteBuddy 检测传出方法/构造函数调用吗?【英文标题】:Can I instrument outgoing method/constructor calls with ByteBuddy? 【发布时间】:2017-11-13 13:47:42 【问题描述】:我有一个项目,我使用 Javassist 记录传出的方法/构造函数调用,代码如下:
CtMethod cm = ... ;
cm.instrument(
new ExprEditor()
public void edit(MethodCall m)
throws CannotCompileException
if (m.getClassName().equals("Point")
&& m.getMethodName().equals("move"))
m.replace(" $1 = 0; $_ = $proceed($$); ");
);
它将'0'分配给被调用方法的第一个参数,然后继续进行原始调用,也就是说,如果cm
代表方法someMethod
,我们将传出调用从someMethod
修改为Point::move
:
public int someMethod(int arg1)
Point p;
...
Point newPoint =
//Here we start tampering with the code
p.move(0, arg2, arg3, arg4); //Say it was originally p.move(arg1, arg2, arg3, arg4);
//From here we leave it as it was
...
我现在正尝试迁移到 ByteBuddy,因为我希望这些类与(在线)JaCoCo 兼容。我已经设法“从内部”检测方法和构造函数(检测被调用的方法本身),但我还没有找到任何“从外部”实现它的方法(检测从其他地方对此类方法的调用)。 ByteBuddy 有什么办法吗?
这个问题与 another which asked for a way to catch constructor exceptions 有关,因为这是我使用 Javassist 实现它的方式。
【问题讨论】:
【参考方案1】:您可以使用Advice
更改方法的参数,它允许您在执行原始方法之前更改参数:
@Advice.OnMethodEnter
static void enter(@Advice.Argument(value = 0, readOnly = false) int arg)
arg = 0;
这样做,上述代码将被添加到您需要使用ElementMatcher
(如named("move")
)定位的move
方法中。
【讨论】:
代替参数,有没有办法改变方法的主体?具体来说,我想查找方法中存在的特定库调用(如ArrayList.add()
),并希望在它之前添加一行代码。
如果您想添加自己的字节码,您可以替换方法,并且替换API相当可扩展。更简单的 DSL 仍在制作中。
我有更详细的查询here。请考虑帮助我!以上是关于我可以使用 ByteBuddy 检测传出方法/构造函数调用吗?的主要内容,如果未能解决你的问题,请参考以下文章
字节码JavaAgent ByteBuddy操作监控方法 字节码