Spring AOP Pointcut 与 CompletableFuture.supplyAsync 结合

问题描述 投票:0回答:1

我想用切入点来测量方法的执行时间,我用 CompletableFuture.supplyAsync 调用它。 目前,我只能触发一个方法,其中包含 CompletableFuture.supplyAsync,但不能触发方法,该方法将从 CompletableFuture.supplyAsync 执行。

这里我想测量 startProcess 方法:

@Async
    public CompletableFuture<Void> myHandler(MyList request) {
        CompletableFuture<Void> result = null;
        for (MyEntity entity : request.getEntities()) {
            result = CompletableFuture.supplyAsync(() -> selectRequiredProcess(entity), Runnable::run)
                    .thenAccept(case ->
                            log.info("success ")
                    .exceptionally(err -> {                        
                        return null;
                    });
        }
        return result;
    }

    public CompletableFuture<String> selectRequiredProcess(MyEntity entity) {
        startNewProcess(entity);
        return CompletableFuture.completedFuture(entity.getCaseId());
    }

    public void startNewProcess(InExkassodaten inExkassodaten) {
        //do stuff...
    }

我的切入点看起来像这样:

 @Around("execution(* my.bbb.StartProcessService.*(my.bb.MyEntity))")
    public Object executionTime(ProceedingJoinPoint point) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object object = point.proceed();
        long endtime = System.currentTimeMillis();
        log.info("Class Name: {} . Method Name: {} . Time taken for Execution is : {} ms",
                point.getSignature().getDeclaringTypeName(), point.getSignature().getName(),
                (endtime - startTime));
        return object;
    }

但不会触发我从 CompletableFuture.supplyAsync 调用的方法。 我只能触发“myHandler”方法。

spring-aop completable-future pointcut
1个回答
0
投票

这实际上是许多类似问题的重复。例如,我正在here解释问题和可能的解决方案。简而言之:基于代理的 Spring AOP 在方法自调用的情况下不起作用,只有本机 AspectJ 可以。一种解决方法是将调用的方法分解到辅助组件中。

package de.scrum_master.spring.q78768043;

public class MyEntity {
  String caseId;

  public MyEntity(String caseId) {
    this.caseId = caseId;
  }

  public String getCaseId() {
    return caseId;
  }
}
package de.scrum_master.spring.q78768043;

public class MyList {
  public MyEntity[] getEntities() {
    return new MyEntity[] { new MyEntity("one"), new MyEntity("two") };
  }
}
package de.scrum_master.spring.q78768043;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

@Service
public class StartProcessService {
  @Autowired
  HelperComponent helperComponent;

  @Async
  public CompletableFuture<Void> myHandler(MyList request) {
    CompletableFuture<Void> result = null;
    for (MyEntity entity : request.getEntities()) {
      result = CompletableFuture.supplyAsync(() -> helperComponent.selectRequiredProcess(entity), Runnable::run)
        .thenAccept(System.out::println);
    }
    return result;
  }

  @Component
  public static class HelperComponent {
    public CompletableFuture<String> selectRequiredProcess(MyEntity entity) {
      startNewProcess(entity);
      return CompletableFuture.completedFuture(entity.getCaseId());
    }

    public void startNewProcess(MyEntity myEntity) {
      //do stuff...
    }
  }
}
package de.scrum_master.spring.q78768043;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {
  @Around("execution(* StartProcessService.HelperComponent.*(MyEntity))")
  public Object executionTime(ProceedingJoinPoint point) throws Throwable {
    long startTime = System.currentTimeMillis();
    Object object = point.proceed();
    System.out.printf(
      "Class Name: %s . Method Name: %s . Time taken for Execution is : %d ms%n",
      point.getSignature().getDeclaringTypeName(), point.getSignature().getName(),
      System.currentTimeMillis() - startTime
    );
    return object;
  }
}
package de.scrum_master.spring.q78768043;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class DemoApplication {
  public static void main(String[] args) {
    try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
      doStuff(appContext);
    }
  }

  private static void doStuff(ConfigurableApplicationContext appContext) {
    appContext.getBean(StartProcessService.class).myHandler(new MyList());
  }
}

运行应用程序以查看以下控制台日志:

Class Name: de.scrum_master.spring.q78768043.StartProcessService$HelperComponent . Method Name: selectRequiredProcess . Time taken for Execution is : 13 ms
java.util.concurrent.CompletableFuture@24842b8e[Completed normally]
Class Name: de.scrum_master.spring.q78768043.StartProcessService$HelperComponent . Method Name: selectRequiredProcess . Time taken for Execution is : 0 ms
java.util.concurrent.CompletableFuture@146add7b[Completed normally]
© www.soinside.com 2019 - 2024. All rights reserved.