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

我有复杂的@RestController 方法,如下所示:


@PostMapping("{id}")

@PreAuthorize("hasRole('ADMIN')")

@Transactional

public Response handleRequest(@PathVariable("id") long id, @RequestBody @Valid Request request) {

    return service.handleRequest(id, request);

}

我们的请求处理非常慢,因此我们想检查在特定请求处理任务上花费了多少时间。不幸的是,很多事情都是在我的方法之外完成的,比如:

  • 反序列化请求

  • 证实

  • 权限检查

  • 开始和结束交易

  • 序列化响应

有没有办法简单地测量所有这些部分?也许是一组接收跟踪消息的记录器,以便我可以在每个步骤结束时提取时间戳?

我现在看到的唯一方法是更改该方法以接受 HttpServletRequest 和 HttpServletResponse 并在方法主体内执行这些部分。但是那样我会失去很多 Spring Boot 的好处。


蛊毒传说
浏览 155回答 3
3回答

守着一只汪

您还可以检查 tuto 为执行器添加自定义指标,但这似乎有点复杂(但是您必须编写自己的指标 bean 并将其注入代码中,覆盖 objectMapper 以进行映射等... )或者可能激活 jackson、spring-security、javax.validation 上的日志信息,以检查每个操作的日志时间,但不是很精确

哔哔one

你真正需要的是 Java Thread Profiler,它会告诉你到底出了什么问题,你可以使用任何 APM 工具,我最喜欢的是 GLOWROOT 。我在类似的场景中使用它来测量 API 的性能并识别慢跟踪将清楚地告诉您哪个方法正在花费时间,您可以看到从方法调用开始到内部调用的所有方法的整个跟踪,甚至可以识别慢查询(如果有的话)。希望这可以帮助该网站:https ://glowroot.org/示例跟踪:https://demo.glowroot.org/transaction/thread-profile?transaction-type=Web&transaction-name=%2Fhot-sauces

九州编程

无需更改方法即可期待 HttpServletRequest。您可以使用AspectJ使用它,您可以收集在每种方法上花费的时间并从中分析数据。创建一个方法计时注释@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface MethodTiming {}在您的请求中,创建一个地图,以保留所有方法及其所用时间:&nbsp; public class Request {&nbsp; private Map<String, Long> methodTimings = new TreeMap<String, Long>();&nbsp; public void addMethodTiming(String classAndMethodName, long executionTimeMillis) {&nbsp; &nbsp; &nbsp; &nbsp; Long value = methodTimings.get(classAndMethodName);&nbsp; &nbsp; &nbsp; &nbsp; if (value != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; executionTimeMillis += value;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; methodTimings.put(classAndMethodName, executionTimeMillis);&nbsp; &nbsp; }&nbsp; }然后,创建将处理它的 Aspect 类:@Aspect@Componentpublic class MethodTimingAspect {private static final String DOT = ".";@Around("@annotation(MethodTiming)")public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable&nbsp; {&nbsp; &nbsp; Object result = null;&nbsp; &nbsp; StopWatch watch = new StopWatch();&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; watch.start();&nbsp; &nbsp; &nbsp; &nbsp; result = joinPoint.proceed();&nbsp; &nbsp; } finally {&nbsp; &nbsp; &nbsp; &nbsp; watch.stop();&nbsp; &nbsp; &nbsp; &nbsp; long executionTime = watch.getLastTaskTimeMillis();&nbsp; &nbsp; &nbsp; &nbsp; String className = joinPoint.getTarget().getClass().getSimpleName();&nbsp; &nbsp; &nbsp; &nbsp; String methodName = joinPoint.getSignature().getName();&nbsp; &nbsp; &nbsp; &nbsp; String classAndMethodName = className + DOT + methodName;&nbsp; &nbsp; &nbsp; &nbsp; Object[] methodArgs = joinPoint.getArgs();&nbsp; &nbsp; &nbsp; &nbsp; if (methodArgs != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (Object arg : methodArgs) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (arg instanceof Request) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // inject time back into Request&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Request request = (Request) arg;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request.addMethodTiming(classAndMethodName, executionTime);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return result;}最后,只需在您希望测量的方法上添加@MethodTiming:@MethodTimingpublic Request handleRequest(Request request) {// handle the Requestreturn request}您的请求对象将在处理之后拥有类似的东西"methodTimings": {&nbsp; &nbsp; "RequestService.handleRequest": 2610,&nbsp; &nbsp; "AnotherRequestService.anotherMethod": 1351}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java