java - 使用 Javassist 或 ASM 拦截字段访问

标签 java java-bytecode-asm javassist bytecode-manipulation

我熟悉使用代理拦截方法调用的各种方法,但我想知道是否有一种方法可以使用 Javassist 或 ASM 等库来检测某些代理上的字段访问/取消引用?例如:

void detectFieldName(Function<Foo, Supplier<String>> f) {
  Foo fooProxy = createFooProxy();
  f.apply(fooProxy);
}

detectFieldName((Foo foo) -> foo.bar);

理想情况下,我想知道名为 bar 的字段已取消引用。

最佳答案

看看您更新的用例:lambda 被脱糖为合成(编译器生成)方法,并带有一个通过生成的方法转发接口(interface)调用的函数对象(我还没有具体研究这是如何实现的,但我认为Brian Goetz 已经谈到过这一点)。您只需查看该方法的字节码(从类文件加载;一些 ASM 示例代码执行此操作)并读取字段访问。不需要仪器。

请注意,您无法创建代理来查看字段访问;字段访问是在 lambda 方法(或者更一般地说,加载字段的地方)中执行的,而不在 Foo 中执行任何代码。事实上,如果您只想获取字段名称,您甚至不需要调用 lambda,并且如果您使用 Foo 代理只是为了调用,则不需要代理。

<小时/>

我不知道有什么方法可以像 java.lang.reflect.Proxy 拦截方法调用那样轻松地拦截字段访问。

getfieldputfield 字节码使用对类和字段名称进行编码的符号描述符,因此您可以使用 Java agent在每次加载和存储之前或之后添加方法调用,传递正在加载/存储的字段名称、对象和值。 (如果您只对字段的子集(例如特定类的所有字段)感兴趣,则这种方法效果最佳。)根据您的需要,您可能还必须通过使用 java.lang.Instruction 来识别对字段的反射访问。 lang.reflect.Field,MethodHandles.Lookup.findGetter/Setter返回的句柄等(可能涉及过程间分析或用于构建字段名称的字符串操作的推理等) )。您还可以尝试在库调用某些特定于 JVM 的 native 功能“之前”进行检测,但这会将您与一个 JVM 实现联系起来,并且如果 JVM 内在反射调用(特殊情况下的代码生成),您的检测可能会被跳过。

如果您愿意编写C代码,您可以使用JVM工具接口(interface)watched field functions 。这似乎是获取信息的最简单方法,但是用它来做有趣的 Java 级别的事情却比较困难(尽管您可以从 JVMTI 回调到 Java 支持库)。

关于java - 使用 Javassist 或 ASM 拦截字段访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23839945/

相关文章:

java - 如何从 Java 中保存带有 tEXt 或 iTXt block 的 PNG?

java - 构造函数不支持@Override

java - ISO 9797-1 MAC算法3和填充方法1 Java示例?

java - 为什么 ASM 无法为我的生成类计算出正确的最大值?

playframework - 在 helpers.CheatSheetHelper$2 无效常量类型 : 15 上 Play 1.2.x UnexpectedException ContinuationEnhancer

java - 我可以在运行时修改 Java 方法的字节码吗?

Java - 日期格式

java - 在 catch 上调用什么 ASM 访问者方法来进行类型注释

Java 字节码 asm - 如何创建仅更改类名的类的克隆?

java - 如何使用 Javassist 进行字节码操作以解决链接错误?