使用Byte Buddy轻松实现Java Agent

本文介绍了如何使用ByteBuddy这个库来创建Java Agent,以实现对目标应用程序的字节码级别的修改,特别是在实现方法级安全方面。ByteBuddy提供了一个友好的API,帮助开发者克服直接操作字节码的复杂性,使得动态增强或修改类的行为变得更加简单。文章通过示例展示了如何使用ByteBuddy创建代理,以在运行时动态地添加安全检查,防止未经授权的访问。
摘要由CSDN通过智能技术生成

Java agent是在另一个Java应用程序(“目标”应用程序)启动之前执行的Java程序,为该agent提供修改目标应用程序或其运行环境的机会。在本文中,我们将从基础知识开始,使用字节码操作工具Byte Buddy实现高级代理。

在最基本的用例中,Java agent设置应用程序属性或配置特定的环境状态,从而使代理能够充当可重用和可插入的组件。下面的示例描述了这样一个代理agent,它设置了可供实际程序使用的系统属性:

public class Agent {
  public static void premain(String arg) {
    System.setProperty("my-property", “foo”);
  }
}

正如上面的代码所演示的,Java agent的定义与任何其他Java程序一样,只是 premain 将 main 方法替换为入口点。顾名思义,此方法在目标应用程序的主方法之前执行。除了适用于任何其他Java程序的标准规则之外,没有其他特定的编写agent代理的规则。作为最小的区别,Java agent接收单个可选参数,而不是零个或多个参数的数组。

要启动agent代理,必须将agent类和资源捆绑在一个jar中,并在jar manifest中将代理类属性设置为包含 premain 方法的代理类的名称(代理必须始终绑定为jar文件,不能以分解格式指定。)接下来,必须通过命令行上的 javaagent 参数引用jar文件的位置来启动应用程序:

java -javaagent:myAgent.jar -jar myProgram.jar

还可以将可选代理参数前置到此位置路径。以下命令启动Java程序,并将提供值 myOptions 作为参数的给定代理附加到 premain 方法:

java -javaagent:myAgent.jar=myOptions -jar myProgram.jar

通过重复 javaagent 命令可以附加多个代理。

然而,Java agent的功能远不止改变应用程序环境的状态;Java代理可以被授予访问Java instrumentation API的权限,从而允许代理修改目标应用程序的代码。Java虚拟机的这一鲜为人知的特性提供了一个强大的工具,可以促进面向方面编程的实现。

关于Java Instrumentation可以参考这篇文章: https://javakk.com/2237.html

通过向agent代理的 premain 方法添加第二个Instrumentation类型的参数,可以应用Java程序的这种修改。Instrumentation参数可用于执行一系列任务,从确定对象的确切大小(以字节为单位),到通过注册 ClassFileTransformers 来实际修改类实现。注册后,任何类装入器在装入类时都会调用 ClassFileTransformer 。调用时,类文件转换器有机会在加载所表示的类之前转换甚至完全替换任何类文件。通过这种方式,可以在类投入使用之前增强或修改类的行为,如下例所示:

public class Agent {
 public static void premain(String argument, Instrumentation inst) {
   inst.addTransformer(new ClassFileTransformer() {
     @Override
     public byte[] transform(
       ClassLoader loader,
       String className,
       Class<?> classBeingRedefined, // null if class was not previously loaded
       ProtectionDomain protectionDomain,
       byte[] classFileBuffer) {
       // return transformed class file.
     }
   });
 }
}

在将上述 ClassFileTransformer 注册到一个 Instrumentation 实例之后,每次加载一个类时都会调用该转换器。为此,转换器 transformer 接收类文件的二进制表示形式和对试图加载此类的类加载器的引用。

Java agent也可以在Java应用程序运行时注册。在这种情况下,instrumentation API允许重新定义已加载的类,这一特性称为“热更新”。不幸的是,重新定义加载的类仅限于替换方法体。在重新定义类时,不能添加或删除任何成员,也不能更改任何类型或签名。第一次加载类时,此限制不适用,并且在这些情况下, classBeingRedefined 参数设置为null。

Java字节码和类文件格式

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值