我有以下代码:
@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函数的执行,并标识生成该lambda函数的线程的ID,即我的“ execute”函数在其中运行的线程。我知道如何捕获lambda函数-
execution(void lambda$*(..)
但是对于我来说,识别创建该线程的线程ID(称为“执行”的线程ID)为时已晚,因为lambda在新线程中运行。如何获得“父”线程ID /“执行”线程ID?
您在这里有几个问题:
AspectJ当前无法通过execution()
切入点编织到lambda中。这主要是由于AspectJ编译器/编织器忽略了JVM指令invokedynamic
。另请参见AspectJ票证#471347 (created by myself)和#364886。此外,如果您改用匿名Runnable
类,则可以轻松拦截它。
您不是自己创建和启动线程,而是将其推迟到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())