为通过 lambda 表达式调用的 Runnable.run 方法执行 @Before 和 @After 方面 [英] execute @Before and @After aspect for Runnable.run method which invoked through lambda expression

查看:35
本文介绍了为通过 lambda 表达式调用的 Runnable.run 方法执行 @Before 和 @After 方面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说明如何为 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.

  1. 为 Runnable.run 方法创建切入点
  2. 在步骤 1 中为切入点创建 @Before 方面.---> 运行前打印
  3. 在步骤 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆