利用自定义注解,统计方法执行时间

项目中需要统计某些方法的执行时间,最简易的方式是方法执行前记录时间戳startTime,在方法结束前,用时间戳endTime-startTime得出该方法耗时。
但是为了避免无代码侵入并实现通用,于是定义一个注解,如果要统计哪个方法,只需在方法上写上注解即可,通过注解可以获取到方法的参数、方法名、返回值等等信息。

下面是一个简单的时间统计实现:

1.定义一个注解TimeConsume

该注解有一个默认的value属性,value值为方法名或自定义的描述

1
2
3
4
5
6
7
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TimeConsume {

String value() default "方法";
}

2.使用Aspect定义该注解的切面TimeConsumeAspect

定义好注解后,需要对该注解使用的类进行监听,利用Spring框架Aspect实现切面,定义环绕通知,获取到方法的参数、方法名等信息,便于统计所需。对执行方法进行异常捕获,在finally代码块中实现时间统计逻辑,避免方法异常无法统计。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Slf4j
@Component
@Aspect
public class TimeConsumeAspect {

/**
* 切点定义为注解@annotation(注解类路径)
*/
@Pointcut("@annotation(com.weiller.demo.common.annotation.TimeConsume)")
public void consume(){
}

@Around("consume()")
public <T> T around(ProceedingJoinPoint pjp) throws Throwable {
Long startTime = System.currentTimeMillis();

Object[] args = pjp.getArgs();
T result;
Method methodClass;
try {

result = (T)pjp.proceed(args);//执行方法

}finally {
long endTime = System.currentTimeMillis();
Signature signature = pjp.getSignature();
String methodName = signature.getName();
Class<?> targetClass = pjp.getTarget().getClass();
Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes();
methodClass = targetClass.getMethod(methodName, parameterTypes);
Annotation[] annotations = methodClass.getAnnotations();
for (Annotation annotation : annotations){
Class<? extends Annotation> aClass = annotation.annotationType();
String simpleName = aClass.getSimpleName();
if("TimeConsume".equals(simpleName)){
TimeConsume timeConsume = (TimeConsume) annotation;
String value = timeConsume.value();
log.info(value+"[{}] 执行耗时:{}ms",methodName,endTime-startTime);
break;
}
}

}

return result;
}
}

3.测试目标方法中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RestController
@RequestMapping("/test")
public class testController {

@TimeConsume("测试")
@GetMapping("info")
public Object testInfo(){
Object parse = JSONObject.parse("{\n" +
"\t\t\"requestId\":\"\",\n" +
"\t\t\"appId\":\"\",\n" +
"\t\t\"nonce\":\"\",\n" +
"\t\t\"timestamp\":12345676543,\n" +
"\t\t\"signature\":\"\",\n" +
"\t\t\"sjgsd\":\"61000\",\n" +
"\t\t\"starTime\":12345676543\n" +
"\t}");
try {
Thread.sleep(new Random().nextInt(100));//随机时间休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
return parse ;
}
}
继续努力吧!来一个