java - AspectJ - 使用aspectJ 获取生成lambda 函数的父线程的线程id

标签 java multithreading aspectj

我有以下代码:

@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/

相关文章:

java - @Secured 注释在使用 Autoproxy 的 AspectJ 模式下不起作用

java - 类/对象转换

c++ - 为什么 “memory_order_relaxed”在我的系统中被视为 “memory_order_seq_cst” [C++]

java - EntityManager 未正确注入(inject),始终为 null

java - 'nested'注释的Spring AOP切入点

java - 什么是用于覆盖参数的 AspectJ 声明语法

JAVA:InputStream.read中的字节数组分配(byte[] b, int off, int len)

java - 通过JAVA应用程序运行unix shell脚本

java - 在 GUI 中处理未处理的异常

python - 无限递归 vs while True?