引语
作为工程师,不能仅仅满意于实现了现有的成果逻辑,还必需深入认识系统。一次请求,流经了哪些要领,执行了几多次DB操纵,会见了几多次文件操纵,挪用几多次API操纵,总共有几多次IO操纵,几多CPU操纵,各耗时几多 ? 开拓者该当知道这些运行时数据,才气对系统的运行有更深入的领略,更好滴晋升系统的机能和不变性。
完成一次订单导出任务,实际上是一个较量巨大的进程:需要会见ES 来查询订单,挪用批量API接口 及会见 Hbase 获取订单详情数据,名目化报表字段数据,写入和上传报表文件,更新数据库,上报日志数据等;在大流量导出的景象下,回收批量并发计策,多线程来获取订单详情数据,劳务派遣管理系统,整个请求的执行流程会越发巨大。
本文主要先容利用AOP拦截器来获取一次请求流经要领的挪用次数和挪用耗时。
总体思路
利用AOP思想来办理。增加一个注解,然后增加一个AOP methodAspect ,记录要领的挪用次数及耗时。
methodAspect 内部含有两个变量 methodCount, methodCost ,都回收了 ConcurrentHashMap 。这是因为要领执行时,大概是多线程写入这两个变量。
利用:
(1) 将需要记录次数和耗时的要领加上 MethodMeasureAnnotation 即可;
(2) 将 MethodMeasureAspect 作为组件注入到 ServiceAspect 中,并在 ServiceAspect 中打印 MethodMeasureAspect 的内容。
存眷哪些要领
凡是重点存眷一个任务流程中的如下要领:
一般会合在如下包:
源代码
package zzz.study.aop; import zzz.study.util.MapUtil; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.IntSummaryStatistics; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** * 记录一次请求中,流经的所有要领的挪用耗时及次数 * */ @Component @Aspect public class MethodMeasureAspect { private static final Logger logger = LoggerFactory.getLogger(MethodMeasureAspect.class); private Map<String, Integer> methodCount = new ConcurrentHashMap(); private Map<String, List<Integer>> methodCost = new ConcurrentHashMap(); @SuppressWarnings(value = "unchecked") @Around("@annotation(zzz.study.aop.MethodMeasureAnnotation)") public Object process(ProceedingJoinPoint joinPoint) { Object obj = null; String className = joinPoint.getTarget().getClass().getSimpleName(); String methodName = className + "_" + getMethodName(joinPoint); long startTime = System.currentTimeMillis(); try { obj = joinPoint.proceed(); } catch (Throwable t) { logger.error(t.getMessage(), t); } finally { long costTime = System.currentTimeMillis() - startTime; logger.info("method={}, cost_time={}", methodName, costTime); methodCount.put(methodName, methodCount.getOrDefault(methodName, 0) + 1); List<Integer> costList = methodCost.getOrDefault(methodName, new ArrayList<>()); costList.add((int)costTime); methodCost.put(methodName, costList); } return obj; } public String getMethodName(ProceedingJoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); return method.getName(); } public String toString() { StringBuilder sb = new StringBuilder("MethodCount:\n"); Map<String,Integer> sorted = MapUtil.sortByValue(methodCount); sorted.forEach( (method, count) -> { sb.append("method=" + method + ", " + "count=" + count+'\n'); } ); sb.append('\n'); sb.append("MethodCosts:\n"); methodCost.forEach( (method, costList) -> { IntSummaryStatistics stat = costList.stream().collect(Collectors.summarizingInt(x->x)); String info = String.format("method=%s, sum=%d, avg=%d, max=%d, min=%d, count=%d", method, (int)stat.getSum(), (int)stat.getAverage(), stat.getMax(), stat.getMin(), (int)stat.getCount()); sb.append(info+'\n'); } ); sb.append('\n'); sb.append("DetailOfMethodCosts:\n"); methodCost.forEach( (method, costList) -> { String info = String.format("method=%s, cost=%s", method, costList); sb.append(info+'\n'); } ); return sb.toString(); } }