ko-time核心代码
核心逻辑就是对方法做切面,方法执行前后有start和end时间的计算,然后打印出end-start耗时
ko-time对性能有影响,并且为单体架构,只建议在开发环境使用,目前市场中常用的为skywalking,增对微服务架构
ko-time接口可参考官方文档,在这里不做说明
获取调用链路,接口方法函数数据库表耗时,在这里不做说明
关键注解如下:
是否登录注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
String value() default "";
}
计算时间注解,可在依赖此jar后使用注解来获取耗时
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ComputeTime {
String value() default "chinese";
}
关键反射:
反射登录注解,判断是否登录
@Aspect
@Component
public class AuthHandler {
public static Logger log = Logger.getLogger(AuthHandler.class.toString());
@Pointcut(KoConstant.authRange)
public void preProcess() {
}
@Around("preProcess()")
public Object doAroundCompute(ProceedingJoinPoint pjp) throws Throwable {
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
boolean needAuth = method.isAnnotationPresent(Auth.class);
if (needAuth&& Context.getConfig().getAuthEnable()) {
KoUtil.checkLogin();
}
return pjp.proceed();
}
}
反射计算时间注解,从切面计算方法运行时间
@Aspect
@Component
public class ComputeTimeHandler {
public static Logger log = Logger.getLogger(ComputeTimeHandler.class.toString());
@Pointcut(KoConstant.comMethodRange)
public void preProcess() {
}
@Around("preProcess()")
public Object doAroundCompute(ProceedingJoinPoint pjp) throws Throwable {
ComputeTime computeTime = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotation(ComputeTime.class);
long begin = System.nanoTime();
Object obj = pjp.proceed();
long end = System.nanoTime();
if ("chinese".equals(computeTime.value())) {
log.info("调用方法=" + pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName() + ",耗时=" + ((end - begin) / 1000000) + "毫秒");
} else {
log.info("method=" + pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName() + ",runTime=" + ((end - begin) / 1000000) + "ms");
}
return obj;
}
}
设置advice,将RunTimeHandler放入
@Bean
public AspectJExpressionPointcutAdvisor configurabledvisor() {
log.info("kotime=>loading method listener");
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(defaultConfig.getPointcut()==null?pointcut:defaultConfig.getPointcut());
advisor.setAdvice(new RunTimeHandler());
return advisor;
}
设置方法耗时,或者抛出异常,实现了方法拦截器,对方法进行切面,这是本身ko-time的接口耗时实现
public class RunTimeHandler implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
boolean kotimeEnable = Context.getConfig().getEnable();
if (!kotimeEnable) {
return invocation.proceed();
}
boolean exceptionEnable = Context.getConfig().getExceptionEnable();
long begin = System.nanoTime();
Object obj = null;
MethodNode parent = InvokeService.getParentMethodNode();
MethodStack.record(invocation);
if (exceptionEnable) {
try {
obj = invocation.proceed();
} catch (Exception e) {
ExceptionNode exception = new ExceptionNode();
exception.setName(e.getClass().getSimpleName());
exception.setClassName(e.getClass().getName());
exception.setMessage(e.getMessage());
exception.setValue(e.getStackTrace()[0].getLineNumber());
exception.setId(exception.getClassName() + exception.getName() + exception.getMessage());
MethodNode current = InvokeService.getCurrentMethodNode(invocation, 0.0);
if (current.getClassName().equals(e.getStackTrace()[0].getClassName())) {
GraphService graphService = GraphService.getInstance();
graphService.addMethodNode(current);
graphService.addExceptionNode(exception);
graphService.addExceptionRelation(current, exception);
}
MethodStack.clear();
throw e;
}
} else {
obj = invocation.proceed();
}
long end = System.nanoTime();
MethodNode current = InvokeService.getCurrentMethodNode(invocation, ((end - begin) / 1000000.0));
GraphService graphService = GraphService.getInstance();
graphService.addMethodNode(parent);
graphService.addMethodNode(current);
graphService.addMethodRelation(parent, current);
MethodStack.clear();
return obj;
}
}