我可以使用 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操作监控方法 字节码

Java字节码-使用ByteBuddy实现一个Java-Agent

Android:检测短信传出,计数不正确

Mockito 动态代理 & ByteBuddy

ByteBuddy(史上最全)

ByteBuddy(史上最全)