使用 AspectJ 监视 运行 启动应用程序中 REST 调用的时间

Using AspectJ to monitor run time of a REST call within Spring Boot app

我有一个 Spring 启动应用程序,其中包含多个 classes,它们共享一个通用的 HttpUtil class,它发出 Http 请求。过去,我在以下方面使用了 AspectJ:

@Around("execution(* com.gateway.TestGateway.getStatus(..))")
public Object GatewayStatus(ProceedingJoinPoint pjp) throws Throwable {
    StopWatch watch = new StopWatch();
    watch.start();
    Object output = pjp.proceed();
    watch.stop();
    log.error("Call took - [" + (watch.getTime()) + "]ms");
    return output;
}

这很好用,我将 getStatus() 方法与 @Around 注释匹配,但网关结构现在有围绕 httputil 调用的代码,我只想分析其余调用.新的网关方法如下所示:

final HttpUtil httpUtil; //Constructor injected by Spring.

public ResponseEntity<String> getResponse(final String serviceUrl, final HttpEntity<String> httpEntity) throws Exception  {

    ResponseEntity<String> response = null;
    //Code here to verify the Entity
    try{
        response = httpUtil.postEntity(serviceUrl, httpEntity, String.class,
            httpUtil.getRestTemplate());
        //Logic here to work on the response.
    }
    catch(Exception e){
        log.error("Error occurred");
    }
    return response;
}

我知道我可以重构它,或者在 HttpUtil class 方法本身上使用探查器,但是我如何使用 AspectJ 来匹配现有方法中的代码片段?如,运行 postEntity() 调用开始和 postEntity() 调用完成后 在方法 returns 之前 [=] 18=]

我不太熟悉切入点和其他 AspectJ 属性。我想做的只是记录执行时间,但我想了解有关 AspectJ 的更多信息。

当您在程序中选择要应用建议并执行一些额外代码的点时,例如为 postEntity() 方法调用计时,您必须创建 连接点 pointcut(s) 为您选择的位置。切入点定义了您的建议将应用的连接点(您的计时代码将从哪里开始)。

因此,我认为您的问题具体是关于如何在 ClassThatHasGetResponse class.

中的 postEntity() 调用处定义切入点

记录了描述切入点的不同方法 here and some nice pointcut examples are here

对于你的问题,你可能有这样的切入点:

cflow(execution(Object ClassThatHasGetResponse.com.package.getResponse(..))) && call(* HttpUtil.postEntity(..))

上面的切入点定义了执行控制流在 class ClassThatHasGetResponse 的方法 getResponse() 内部的位置,并且对 postEntity() 进行了方法调用使用任何 return 类型和任何参数。

您必须将此切入点添加到捕获计时数据的@Around 建议,可能像这样:

@Around("cflow(execution(Object ClassThatHasGetResponse.com.package.getResponse(..))) && call(* HttpUtil.postEntity(..))")
public Object GatewayStatus(ProceedingJoinPoint pjp) throws Throwable {
    StopWatch watch = new StopWatch();
    watch.start();
    Object output = pjp.proceed();
    watch.stop();
    log.error("Call took - [" + (watch.getTime()) + "]ms");
    return output;
}

由于您使用的是 Spring,可能还值得注意的是 Spring 对 AOP 的支持(这与 AspectJ 不同,但它是很容易混淆使用一个和另一个 IMO,特别是当第一次通过 Spring 学习 AOP 而使用 AspectJ 时),切入点(由连接点组成)始终是方法执行的一个点,这简化了 AspectJ 的灵活性。 Source