super() 调用的切入点 Java API
Pointcut for super() call to Java API
我正在尝试使用 AspectJ 将调用挂接到 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");
}
}
这很好地挂钩了对 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 class 的情况下做到这一点?
你基本上有两个选择:
- 使用模式
File+
来匹配包含子classes 的切入点。没必要知道他们的名字。
- 使用 AspectJ 二进制(post-编译)编织并将方面代码直接注入 JDK class 中 rt.jar,创建它的修改版本或者只是将修改后的 JDK classes 打包到一个新的 JAR 中并将其添加到引导 classpath.
虽然前一种方法是非侵入式的并且独立于您在运行时环境中修改 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(..))
return 是一个对象,但 execution(*.new(..))
不是,这就是为什么 around()
建议的 return 类型是 void
。这些语义在 AspectJ documentation.
中描述
更新: 您在评论中询问了内部 classes。好吧,我的切入点适用于静态内部 classes,没有任何变化。但是非静态内部 class 在其构造函数中需要其周围 class 的实例。看看这个,我为你创建了一个 class + 调试方面:
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))
正如您在日志末尾看到的那样,内部 class 的构造函数被转换为将周围的 class 实例作为其第一个参数的东西,因此不匹配。现在,知道了这一点,我们可以更改原始切入点以捕获所有构造函数:
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);
}
我正在尝试使用 AspectJ 将调用挂接到 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");
}
}
这很好地挂钩了对 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 class 的情况下做到这一点?
你基本上有两个选择:
- 使用模式
File+
来匹配包含子classes 的切入点。没必要知道他们的名字。 - 使用 AspectJ 二进制(post-编译)编织并将方面代码直接注入 JDK class 中 rt.jar,创建它的修改版本或者只是将修改后的 JDK classes 打包到一个新的 JAR 中并将其添加到引导 classpath.
虽然前一种方法是非侵入式的并且独立于您在运行时环境中修改 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(..))
return 是一个对象,但 execution(*.new(..))
不是,这就是为什么 around()
建议的 return 类型是 void
。这些语义在 AspectJ documentation.
更新: 您在评论中询问了内部 classes。好吧,我的切入点适用于静态内部 classes,没有任何变化。但是非静态内部 class 在其构造函数中需要其周围 class 的实例。看看这个,我为你创建了一个 class + 调试方面:
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))
正如您在日志末尾看到的那样,内部 class 的构造函数被转换为将周围的 class 实例作为其第一个参数的东西,因此不匹配。现在,知道了这一点,我们可以更改原始切入点以捕获所有构造函数:
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);
}