为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 Spring Boot 中分析复杂的 http 请求处理?

如何在 Spring Boot 中分析复杂的 http 请求处理?

蛊毒传说 2022-06-15 17:23:53
我有复杂的@RestController 方法,如下所示:@PostMapping("{id}")@PreAuthorize("hasRole('ADMIN')")@Transactionalpublic Response handleRequest(@PathVariable("id") long id, @RequestBody @Valid Request request) {    return service.handleRequest(id, request);}我们的请求处理非常慢,因此我们想检查在特定请求处理任务上花费了多少时间。不幸的是,很多事情都是在我的方法之外完成的,比如:反序列化请求证实权限检查开始和结束交易序列化响应有没有办法简单地测量所有这些部分?也许是一组接收跟踪消息的记录器,以便我可以在每个步骤结束时提取时间戳?我现在看到的唯一方法是更改该方法以接受 HttpServletRequest 和 HttpServletResponse 并在方法主体内执行这些部分。但是那样我会失去很多 Spring Boot 的好处。
查看完整描述

3 回答

?
守着一只汪

TA贡献1872条经验 获得超3个赞

您还可以检查 tuto 为执行器添加自定义指标,但这似乎有点复杂(但是您必须编写自己的指标 bean 并将其注入代码中,覆盖 objectMapper 以进行映射等... )

或者可能激活 jackson、spring-security、javax.validation 上的日志信息,以检查每个操作的日志时间,但不是很精确


查看完整回答
反对 回复 2022-06-15
?
哔哔one

TA贡献1854条经验 获得超8个赞

你真正需要的是 Java Thread Profiler,它会告诉你到底出了什么问题,你可以使用任何 APM 工具,我最喜欢的是 GLOWROOT 。我在类似的场景中使用它来测量 API 的性能并识别慢跟踪将清楚地告诉您哪个方法正在花费时间,您可以看到从方法调用开始到内部调用的所有方法的整个跟踪,甚至可以识别慢查询(如果有的话)。希望这可以帮助

该网站:https ://glowroot.org/

示例跟踪:

https://demo.glowroot.org/transaction/thread-profile?transaction-type=Web&transaction-name=%2Fhot-sauces


查看完整回答
反对 回复 2022-06-15
?
九州编程

TA贡献1785条经验 获得超4个赞

无需更改方法即可期待 HttpServletRequest。您可以使用AspectJ


使用它,您可以收集在每种方法上花费的时间并从中分析数据。


创建一个方法计时注释


@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface MethodTiming {

}

在您的请求中,创建一个地图,以保留所有方法及其所用时间:


  public class Request {

  private Map<String, Long> methodTimings = new TreeMap<String, Long>();


  public void addMethodTiming(String classAndMethodName, long executionTimeMillis) {

        Long value = methodTimings.get(classAndMethodName);

        if (value != null) {

            executionTimeMillis += value;

        }


        methodTimings.put(classAndMethodName, executionTimeMillis);

    }

  }

然后,创建将处理它的 Aspect 类:


@Aspect

@Component

public class MethodTimingAspect {

private static final String DOT = ".";


@Around("@annotation(MethodTiming)")

public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable  {

    Object result = null;


    StopWatch watch = new StopWatch();

    try {

        watch.start();

        result = joinPoint.proceed();

    } finally {

        watch.stop();

        long executionTime = watch.getLastTaskTimeMillis();


        String className = joinPoint.getTarget().getClass().getSimpleName();

        String methodName = joinPoint.getSignature().getName();

        String classAndMethodName = className + DOT + methodName;


        Object[] methodArgs = joinPoint.getArgs();

        if (methodArgs != null) {

            for (Object arg : methodArgs) {

                if (arg instanceof Request) {

                    // inject time back into Request

                    Request request = (Request) arg;

                    request.addMethodTiming(classAndMethodName, executionTime);


                    break;

                }

            }

        }


    }

    return result;

}

最后,只需在您希望测量的方法上添加@MethodTiming:


@MethodTiming

public Request handleRequest(Request request) {

// handle the Request

return request

}

您的请求对象将在处理之后拥有类似的东西


"methodTimings": {

    "RequestService.handleRequest": 2610,

    "AnotherRequestService.anotherMethod": 1351

}


查看完整回答
反对 回复 2022-06-15
  • 3 回答
  • 0 关注
  • 154 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号