改变Java中静态方法的行为 - 字节代码操作

时间:2015-12-27 11:21:01

标签: java bytecode java-bytecode-asm bytecode-manipulation byte-buddy

我正在尝试操纵静态方法。为此,可以使用Byte Buddy或任何其他框架。

有一个名为Pi4J的库用于控制Raspberry Pi的GPIO。该库有一个名为:

的方法
GpioController gpio = GpioFactory.getInstance();

在我可能无法控制的程序的几个地方调用此调用,以便我需要修改调用。

我想要做的是,当GpioFactory.getInstance以某种方式执行时,检测并修改GpioController的方法,以便记录它们已被调用。

也许唯一的解决方案是使用AspectJ,但是你知道Byte Buddy是否可以成为解决方案吗?

2 个答案:

答案 0 :(得分:2)

Pi4J的代码在LGPL许可下的github上是开源的。您可以简单地克隆存储库,根据需要进行修改并使用自己的版本。如果您认为您的更改可以帮助其他人并考虑贡献tp pi4j。

答案 1 :(得分:2)

Java agentByte Buddy结合使用时,完全可以实现这一点。例如,您可以修改GpioFactory::getInstance方法,如以下Java代理所示:

public class MyAgent {
  public static void premain(String arg, Instrumentation inst) {
    new AgentBuilder.Default()
      .type(ElementMatchers.named("com.pi4j.io.gpio.GpioFactory")
      .transform((builder, type) -> // Or anonymous class for pre Java 8
          builder.method(ElementMatchers.named("getInstance"))
                 .intercept(MethodDelegation.to(MyFactory.class));
      ).installOn(inst)
  }
}

public class MyFactory {
  public static GpioController intercept(@SuperCall Callable<GpioController> s) 
       throws Exception {
    return s.call(); // Wrap controller here.
  }
}

使用此代理,从原始getInstance方法返回的任何控制器实例都将通过MyFactory::intercept方法传递。

或者,您可以同等地检测GpioController的所有实现以直接执行日志记录。这将影响界面的所有实例。

如果您无法在启动时在JDK(非标准JVM)上添加Java代理,则可以使用ByteBuddyAgent.install()(来自byte-buddy-agent依赖关系)手动安装代理运行。在这种情况下,您需要确保在加载GpioFactory之前已安装代理。您可以在documentation of the library

中找到更多信息

最后,请注意AspectJ和Byte Buddy都使用Java代理来实现其检测。然而,AspectJ使用自己的语法,其中Byte Buddy用Java模拟其API的主要核心差异。