问题描述
我想将 MDC 上下文映射复制并设置到 Spring 应用程序中由 ForkJoinPool 管理的线程。不幸的是,我无法在 execute 方法上添加 aop,因为 ForkJoinPool 是非托管 spring bean。 我也不能在 ForkJoinTask 上应用 aop。 你知道如何在非 bean 类上应用 aop 吗?或者如何将 MDC 上下文映射复制到 ForkJoinPool?
@Slf4j
@Component
@Aspect
public class ForkJoinTaskAspect {
@Around("execution(* java.util.concurrent.ForkJoinPool.execute(..))")
public Object executionAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
log.debug("ForkJoinTaskAspect:: Before invoking execute() method");
Map<String,String> contextMap = MDC.getcopyOfContextMap();
Object value = null;
try {
MDC.setContextMap(contextMap);
value = proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printstacktrace();
}
finally {
MDC.clear();
}
log.debug("ForkJoinTaskAspect:: After invoking execute() method. Return value=" + value);
return value;
}
}
解决方法
用户 R.G 已经给了您正确的提示,您只能使用原生 AspectJ 为不是 Spring bean 的类提供建议。
在这种情况下,由于您希望在引导类路径上编织到一个 JRE 类,您的任务变得更加复杂,而这对于 AspectJ 来说是不容易实现的。所以除非你想做一些相当难看的事情,比如二进制 JRE 类编织并将编织的 JRE 类放在引导类路径上,否则我建议你只编织到应用程序目标类中,使用 call()
而不是 {{1 }}。这意味着您不会编织被调用者类 execution()
而是所有调用类。这是一个小例子:
ForkJoinPool
package de.scrum_master.app;
import java.util.concurrent.ForkJoinPool;
public class Application {
public static void main(String[] args) throws InterruptedException {
ForkJoinPool.commonPool().execute(() -> {
System.out.println("Task executed in ForkJoinPool");
});
Thread.sleep(100);
}
}
文件 package de.scrum_master.aspect;
import java.util.Map;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.MDC;
@Aspect
public class ForkJoinTaskAspect {
@Around("call(* java.util.concurrent.ForkJoinPool.execute(..))")
public Object executionAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("Before " + proceedingJoinPoint);
Map<String,String> contextMap = MDC.getCopyOfContextMap();
Object value = null;
try {
MDC.setContextMap(contextMap);
value = proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
} finally {
MDC.clear();
}
System.out.println("After " + proceedingJoinPoint);
return value;
}
}
将是:
META-INF/aop.xml
控制台日志将是:
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<aspect name="de.scrum_master.aspect.ForkJoinTaskAspect" />
</aspects>
<weaver options="-showWeaveInfo">
<include within="de.scrum_master.app..*" />
</weaver>
</aspectj>