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

查看:144
本文介绍了对通过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方面. --->在runnbale之前打印
  3. 在步骤1中为切入点创建@Aefore方面. --->运行后打印

在下面的行被调用时

executor.runAsync(() ->

{ System.out.println("Runnable invoked"); }
)

预期输出:

Before runnable
Runnable invoked
After runnable

来自 @AspectJ的解决方案. scala(可能是Java)lambda的切入点在此问题中不起作用.

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的内容,因为目标为null.对于匿名子类,这将起作用.

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更好地支持lambda之前它可以工作.不过,您需要根据调用有问题的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天全站免登陆