AOP封装一个记录耗时的注解
简述
- 上篇文章说的是使用Arthas来分析耗时,但是整体流程还是挺繁琐的,那这篇文章我们就用AOP来封装一个记录耗时的注解吧,虽然做不到分析整个调用链路上的耗时情况,但是我们可以在我们希望记录耗时的方法上加上对应的注解,来记录对应的耗时。
代码实现
- 那现在我们来从头编写一个TakeTimeAspect类,该类通过AOP的方式来监控方法的执行时间,并且记录相关的日志信息。首先导入AOP的依赖
1 | <dependency> |
- 代码实现
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
48
49
50
51
52
53
54
55
56
57
58
59
60import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
public class TakeTimeAspect {
// ThreadLocal变量用于存储开始时间和结束时间
ThreadLocal<Long> startTime = new ThreadLocal<>();
ThreadLocal<Long> endTime = new ThreadLocal<>();
// 定义一个切入点,匹配带有@TakeTimeLog注解的方法
public void TakeTime() {}
// 前置增强方法,在方法执行前记录开始时间
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 获得注解
TakeTimeLog timeLog = getAnnotationLog(joinPoint);
if (timeLog == null) {
return;
}
startTime.set(System.currentTimeMillis());
}
// 返回后增强方法,在方法执行后记录结束时间和执行时间,并记录日志
public void doAfterReturning(JoinPoint joinPoint, Object ret) {
Map<String, Object> resultMap = new HashMap<>();
String[] names = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
if (names.length > 0) {
for (int i = 0; i < names.length; i++) {
if (!(joinPoint.getArgs()[i] instanceof HttpServletRequest)) {
resultMap.put(names[i], joinPoint.getArgs()[i]);
}
}
}
// 处理完请求后,返回内容
log.info("Return:" + JSON.toJSONString(ret));
endTime.set(System.currentTimeMillis());
log.info("Execution Time:" + (endTime.get() - startTime.get()));
}
// 用于获取方法上的注解
private TakeTimeLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(TakeTimeLog.class);
}
return null;
}
}ThreadLocal<Long> startTime
和ThreadLocal<Long> endTime
:这两个是ThreadLocal变量,用于存储方法执行的开始时间和结束时间,用于计算方法的执行时间。ThreadLocal允许存储每个线程特定的数据,确保线程安全性。- 切点表达式:
@Pointcut("@annotation(com.aimc.paperreduction.common.annotation.TakeTimeLog)")
,匹配带有@TakeTimeLog注解的方法。 - 增强方法
@Before("TakeTime()")
:在匹配TakeTime切入点的方法之前执行。它捕获方法执行开始的时间,当然这里也可以获取更多的信息,例如方法参数之类的信息都可以拿到,这里我们根据自身项目的需求来编写。- @
AfterReturning(returning = "ret", pointcut = "TakeTime()")
:这是一个返回后增强方法。它捕获方法的结束时间,记录返回值,并计算并记录执行时间。
getAnnotationLog
:这是一个私有方法,用于从目标方法中获取TakeTimeLog注解(如果存在)。
使用方式
- 我们在需要记录耗时的方法上加上此注解即可
1 |
|
评论