我有以下代码:
@RequestMapping(method = RequestMethod.GET, path = "/execute")
public @ResponseBody
String execute(@RequestParam("name") String input) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
try {
// Do something...
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
return "lambda call";
}
我想使用aspectJ来捕获lambda函数的执行并识别生成它的线程的id - 我的“execute”函数在其中运行的线程。 我知道如何捕获 lambda 函数 -
execution(void lambda$*(..)
但是这对我来说已经太晚了,无法识别创建该线程的线程 ID(称为“执行”的线程 ID),因为 lambda 在新线程中运行。如何获取“父”线程 id/“执行”线程 id?
最佳答案
您遇到了几个问题:
AspectJ 目前无法通过
execution()
编织到 lambda 中切入点。这主要是由于 JVM 指令invokedynamic
被 AspectJ 编译器/编织器忽略。另请参阅 AspectJ 门票 #471347 (created by myself)和 #364886 。另外,如果你使用匿名Runnable
class 代替,您可以轻松拦截它。您不是自己创建和启动线程,而是将其推迟到 JDK 类和方法,如
ExecutorService.execute(Runnable)
,即你也不能编织到他们的execution()
中,只进入他们的call()
由您自己的(方面编织)代码制成。在 Java 中,没有像“父线程”这样的一般概念,您可以通过像
Thread.getParent()
这样的虚构方法从正在执行的线程轻松确定它。或类似的。有一些为线程组实现的父级内容,但这对您没有帮助。
所以你剩下的是这样的间接方式:
驱动程序应用程序:
package de.scrum_master.app;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Application {
String execute(String input) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
try {
doSomething();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
return "lambda call";
}
private void doSomething() throws IOException {}
public static void main(String[] args) throws Exception {
new Application().execute("dummy");
}
}
方面:
package de.scrum_master.aspect;
import java.util.concurrent.ExecutorService;
public aspect MyAspect {
// Catch-all advice for logging purposes
before() : !within(MyAspect) {
System.out.println(" " + thisJoinPoint);
}
// Intercept calls to ExecutorService.execute(*)
before(Runnable runnable) : call(void ExecutorService.execute(*)) && args(runnable) {
System.out.println(Thread.currentThread() + " | " + thisJoinPoint + " -> " + runnable);
}
// Intercept lambda executions
before() : execution(private void lambda$*(..)) {
System.out.println(Thread.currentThread() + " | " + thisJoinPoint);
}
}
控制台日志:
staticinitialization(de.scrum_master.app.Application.<clinit>)
execution(void de.scrum_master.app.Application.main(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(String de.scrum_master.app.Application.execute(String))
execution(String de.scrum_master.app.Application.execute(String))
call(ExecutorService java.util.concurrent.Executors.newSingleThreadExecutor())
call(void java.util.concurrent.ExecutorService.execute(Runnable))
Thread[main,5,main] | call(void java.util.concurrent.ExecutorService.execute(Runnable)) -> de.scrum_master.app.Application$$Lambda$1/2046562095@2dda6444
execution(void de.scrum_master.app.Application.lambda$0())
Thread[pool-1-thread-1,5,main] | execution(void de.scrum_master.app.Application.lambda$0())
call(void de.scrum_master.app.Application.doSomething())
execution(void de.scrum_master.app.Application.doSomething())
关于java - AspectJ - 使用aspectJ 获取生成lambda 函数的父线程的线程id,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60633046/