gpt4 book ai didi

java - super() 调用 Java API 的切入点

转载 作者:行者123 更新时间:2023-11-30 08:04:29 25 4
gpt4 key购买 nike

我正在尝试使用 AspectJ 将调用 Hook 到 Java API。例如,假设我有 java.io.File 的一个方面:

import java.io.File;

aspect FileTest {
File around(String arg0): args(arg0) && call(public File.new(String)) {
throw new RuntimeException("Example");
}
}

这可以很好地 Hook 对 File(String) 构造函数的调用。但是,它不会对以下代码执行任何操作:

public class FileLoophole extends File {
public FileLoophole(String filename) {
super(filename);
}
}

根据https://eclipse.org/aspectj/doc/next/progguide/language-joinPoints.html ,我应该使用execution()切入点来处理super()调用。但是,这不起作用,因为执行点位于 Java API 中,我无法将代码编织到其中。是否有一个切入点来捕获这些 super() 调用站点?有没有办法在事先不知道 FileLoophole 类的情况下做到这一点?

最佳答案

你基本上有两个选择:

  • 使用模式File+ 来匹配包括子类的切入点。无需知道他们的名字。
  • 使用 AspectJ 二进制(编译后)编织并将切面代码直接从 rt.jar 注入(inject)到 JDK 类中,创建它的修改版本,或者只是将修改后的 JDK 类打包到新的 JAR 中并将其添加到启动之前类路径。

虽然前一种方法是非侵入性的,并且与您在运行时环境中修改 JDK 的能力无关,但它也是间接的,并不完全符合您的要求。后一种方法是您所要求的,但可能不是您想要做的事情,除非非常特殊的情况。

驱动程序应用程序:

package de.scrum_master.app;

import java.io.File;

public class FileLoophole extends File {
public FileLoophole(String filename) {
super(filename);
}

public static void main(String[] args) {
new File("file.txt");
new FileLoophole("loophole.txt");
}
}

方面:

package de.scrum_master.aspect;

import java.io.File;

public aspect FileInterceptor {
Object around(String fileName): call(File+.new(String)) && args(fileName) {
System.out.println(thisJoinPoint + " -> " + fileName);
return proceed(fileName);
}

void around(String fileName): execution(File+.new(String)) && args(fileName) {
System.out.println(thisJoinPoint + " -> " + fileName);
proceed(fileName);
}
}

控制台输出:

call(java.io.File(String)) -> file.txt
call(de.scrum_master.app.FileLoophole(String)) -> loophole.txt
execution(de.scrum_master.app.FileLoophole(String)) -> loophole.txt

P.S.:请注意,虽然 call(*.new(..)) 返回一个对象,但 execution(*.new(..)) 不会返回一个对象,这就是为什么 around() 建议的返回类型是 void 的原因。这些语义在AspectJ documentation中描述。 .

<小时/>

更新:您在评论中询问了内部类。好吧,我的切入点适用于静态内部类,无需任何更改。但非静态内部类在其构造函数中需要其周围类的实例。看看这个,我为您创建了一个类+调试方面:

package de.scrum_master.app;

import java.io.File;

public class Application {
private class FileLoophole extends File {
public FileLoophole(String filename) {
super(filename);
}
}

public static void main(String[] args) {
new File("file.txt");
new Application().new FileLoophole("loophole.txt");
}
}
package de.scrum_master.aspect;

public aspect FileInterceptor {
before() : within(de.scrum_master.app.Application) {
System.out.println(thisJoinPoint);
}
}

现在查看控制台日志:

staticinitialization(de.scrum_master.app.Application.<clinit>)
execution(void de.scrum_master.app.Application.main(String[]))
call(java.io.File(String))
call(de.scrum_master.app.Application())
preinitialization(de.scrum_master.app.Application())
initialization(de.scrum_master.app.Application())
execution(de.scrum_master.app.Application())
call(Class java.lang.Object.getClass())
call(de.scrum_master.app.Application.FileLoophole(Application, String))
staticinitialization(de.scrum_master.app.Application.FileLoophole.<clinit>)
preinitialization(de.scrum_master.app.Application.FileLoophole(Application, String))
initialization(de.scrum_master.app.Application.FileLoophole(Application, String))
execution(de.scrum_master.app.Application.FileLoophole(Application, String))

正如您在日志末尾看到的,内部类的构造函数被转换为将周围类实例作为其第一个参数的内容,因此不匹配。现在,知道了这一点,我们可以更改原始切入点以捕获所有构造函数:

void around(): execution(File+.new(..)) {
System.out.println(thisJoinPoint);
proceed();
}

如果您仍然想捕获文件名,事情会变得有点复杂:

void around(String fileName): execution(File+.new(*, String)) && args(*, fileName) {
System.out.println(thisJoinPoint + " -> " + fileName);
proceed(fileName);
}

关于java - super() 调用 Java API 的切入点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31349045/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com