gpt4 book ai didi

java - spring mvc拦截器如何获取方法执行流程

转载 作者:太空宇宙 更新时间:2023-11-04 12:08:05 25 4
gpt4 key购买 nike

我想获得 spring mvc 项目中完整的执行流程及其执行时间。

public class MetricsInterceptor extends HandlerInterceptorAdapter {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
Method method = hm.getMethod();
if (method.getDeclaringClass().isAnnotationPresent(Controller.class)) {
if (method.isAnnotationPresent(Metrics.class)) {
// System.out.println(method.getAnnotation(Metrics.class).value());
System.out.println(method.getName());
}
}
}
return super.preHandle(request, response, handler);
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
}

}

我正在获取带有 @Metrics 注释的 Controller 类和方法来记录一些方法的指标。我想要的是获取整个方法执行流程( Controller -->服务-->DAO)以及每个方法所花费的时间。无论如何可以在 postHandle() 或 afterCompletion() 中获取该信息。请提出建议。

最佳答案

使用 Spring AOP Around 建议可以实现这一点。

编写一个将拦截的切入点

  • 包及其子包中公共(public)方法的所有执行
  • 并且属于包及其子包
    • Controller 层
    • 服务层(可选择仅限于特定服务)
    • DAO 层

然后写下周围建议如下

@Component
@Aspect
public class TraceAdvice {

@Around("execution(* com.test..*(..)) &&" + " (within(com.test.controller..*) || "
+ "(within(com.test.service..*) && this(com.test.service.TestService)) || " + "within(com.test.dao..*))")
public Object traceCall(ProceedingJoinPoint pjp) throws Throwable {
/* This will hold our execution details in reverse order
* i.e. last method invoked would appear first.
* Key = Full qualified name of method
* Value = Execution time in ms
*/
Map<String, Long> trace = null;
Signature sig = pjp.getSignature();
// Get hold of current request
HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// check if we are in controller (I used RestController modify it if Controller is required instead)
boolean isController = sig.getDeclaringType().isAnnotationPresent(RestController.class);
if (isController) {
// set the request attributte if we are in controller
trace = new LinkedHashMap<>();
req.setAttribute("trace", trace);
} else {
// if its not controller then read from request atributte
trace = (Map<String, Long>) req.getAttribute("trace");
}
Object result = null;
StopWatch watch = new StopWatch();
try {
// start the timer and invoke the advised method
watch.start();
result = pjp.proceed();
} finally {
// stop the timer
watch.stop();
String methodName = sig.getDeclaringTypeName() + "." + sig.getName();
// make entry for the method name with time taken
trace.put(methodName, watch.getTotalTimeMillis());
if (isController) {
// since controller method is exit point print the execution trace
trace.entrySet().forEach(entry -> {
System.out.println("Method " + entry.getKey() + " took " + String.valueOf(entry.getValue()));
});
}
}
return result;
}
}

进行必要的配置后,示例输出应如下所示

Method com.test.dao.TestDAO.getTest took 350
Method com.test.service.TestService.getTest took 1954
Method com.test.controller.TestController.getTest took 3751

或者可以为每个拦截特定包编写三个切入点和相应的 Around 建议,以便消除检查 Controller 的 if-else 部分

我已经测试了设置

  • Spring 4.3.2 发布
  • AspectJ 1.7.4
  • JDK 1.8
  • Tomcat 8.0

如果有任何问题,请在评论中告知。

关于java - spring mvc拦截器如何获取方法执行流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40153833/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com