为通过 lambda 表达式调用的 Runnable.run 方法执行 @Before 和 @After 方面 [英] execute @Before and @After aspect for Runnable.run method which invoked through lambda expression
问题描述
说明如何为 Runnable.run 方法创建切入点,以便在 java 8 lambda 表达式中调用 @Before 和 @After 方面.
Description How to create a pointcut for Runnable.run method So that @Before and @After aspect can be invoked in java 8 lambda expression.
- 为 Runnable.run 方法创建切入点
- 在步骤 1 中为切入点创建 @Before 方面.---> 运行前打印
- 在步骤 1 中为切入点创建 @Aefore 方面.---> 运行后打印
当下面一行被调用时
executor.runAsync(() ->
{ System.out.println("Runnable invoked"); }
)
预期输出:
Before runnable
Runnable invoked
After runnable
来自 @AspectJ 的解决方案.scala(可能还有 java)lambdas 的切入点在这个问题中不起作用.
Solution from @AspectJ. Pointcut for scala (and probably java) lambdas not worked in this problem.
@Around("execution(void com.test..lambda*(..))这将适用于所有 lambda 表达式......我想仅对 Runnable.run 方法进行限制.
@Around("execution(void com.test..lambda*(..)) This will work for all lambda expression ... And I want to restrict this for Runnable.run method only.
推荐答案
你不能,因为执行的 lambda 方法是静态的,即你甚至不能检查像 thisJoinPoint.getTarget() instanceof Runnable
这样的东西,因为目标为空.对于匿名子类,这会起作用.
You cannot because the executed lambda methods are static, i.e. you cannot even check something like thisJoinPoint.getTarget() instanceof Runnable
because the target is null. With anonymous subclasses this would work.
即在对我的 AspectJ Bugzilla 问题 采取措施之前,你真的不能解决这个问题.
I.e. before something has been done about my AspectJ Bugzilla issue, you cannot really solve this problem.
更新:我找到了适合您的解决方法.这并不好,但至少在 AspectJ 更好地支持 lambdas 之前它可以工作.不过,您需要根据调用有问题的 runnable 的方法对其进行调整:
Update: I found a workaround for you. It is not nice, but at least it works until AspectJ supports lambdas better. You need to tailor it to the method calling the runnable in question, though:
驱动程序应用:
package de.scrum_master.app;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class Application {
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
System.out.println("Separate thread lambda");
});
CompletableFuture<Void> future2 = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
try {
MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
System.out.println("Separate thread anonymous Runnable");
}
});
System.out.println("Main thread");
future.get();
future2.get();
}
}
方面:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class AsyncRunInterceptor {
private static final String CLASS_ASYNC_RUN = "java.util.concurrent.CompletableFuture$AsyncRun";
private static final String METHOD_RUN = "run";
@Pointcut("execution(void *(..)) && !within(de.scrum_master.aspect.AsyncRunInterceptor) && if()")
public static boolean isAsyncRun() {
final StackTraceElement[] stackTrace = new Exception().getStackTrace();
if (stackTrace.length < 3)
return false;
final StackTraceElement stackTraceElement = stackTrace[2];
return
stackTraceElement.getClassName() == CLASS_ASYNC_RUN
&& stackTraceElement.getMethodName() == METHOD_RUN;
}
@Before("isAsyncRun()")
public void beforeAsyncRun(JoinPoint thisJoinPoint) {
System.out.println("[" + Thread.currentThread().getId() + "] BEFORE " + thisJoinPoint);
}
@After("isAsyncRun()")
public void afterAsyncRun(JoinPoint thisJoinPoint) {
System.out.println("[" + Thread.currentThread().getId() + "] AFTER " + thisJoinPoint);
}
}
控制台日志:
Main thread
[10] BEFORE execution(void de.scrum_master.app.Application.lambda$0())
[11] BEFORE execution(void de.scrum_master.app.Application.1.run())
Separate thread lambda
Separate thread anonymous Runnable
[11] AFTER execution(void de.scrum_master.app.Application.1.run())
[10] AFTER execution(void de.scrum_master.app.Application.lambda$0())
这篇关于为通过 lambda 表达式调用的 Runnable.run 方法执行 @Before 和 @After 方面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!