2024-03-08 20:17:39
这段代码是基于AspectJ的AOP(面向切面编程)实现,用于在带有特定注解的方法执行前记录开始时间,通常用于日志统计或性能监控。以下是详细解析:
核心功能说明@Before注解
表示这是一个前置通知(Before Advice),会在目标方法执行前触发。
对比其他通知类型:
@After:方法执行后触发
@AfterReturning:方法正常返回后触发
@AfterThrowing:方法抛出异常后触发
@Around:环绕通知,可控制方法是否执行
value = "@annotation(controllerLog)"
指定拦截带有@ControllerLog注解的方法(@ControllerLog是自定义注解,通常用于标记需要记录日志的Controller方法)。
等价写法:
全限定类名:value = "@annotation(com.example.annotation.ControllerLog)"
形参代表:value = "@annotation(controllerLog)"(框架自动注入注解实例)
参数说明
JoinPoint joinPoint:
封装了被拦截方法的上下文信息,可通过它获取:
方法名:joinPoint.getSignature().getName()
参数:joinPoint.getArgs()
目标类:joinPoint.getTarget().getClass()
Log controllerLog:
框架自动注入的注解实例,可通过它获取注解属性(如操作类型、描述等)。
示例:若@ControllerLog定义了value()属性,可通过controllerLog.value()获取。
TIME_THREADLOCAL.set(System.currentTimeMillis())
记录方法开始时间,存储到ThreadLocal变量中,后续可在@After通知中计算执行耗时:@After(value = "@annotation(controllerLog)")public void doAfter(JoinPoint joinPoint, Log controllerLog) { long endTime = System.currentTimeMillis(); long startTime = TIME_THREADLOCAL.get(); long costTime = endTime - startTime; // 存储costTime到数据库或日志}
注解转换逻辑
业务代码中可能使用@Log注解,但通过AOP配置自动转换为@ControllerLog(需确认框架是否支持此特性)。
若存在转换,需确保注解属性兼容,例如:@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Log { String value() default "";}@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface ControllerLog { String operation() default ""; // 需与@Log的value()对应}
IDE支持
IntelliJ IDEA等工具可自动推断controllerLog变量类型,无需显式声明全限定类名。
若类型推断失败,可手动指定:@Before(value = "@annotation(com.example.annotation.ControllerLog controllerLog)")
ThreadLocal的作用
解决多线程环境下时间记录的线程安全问题。
需在请求结束后清理ThreadLocal,避免内存泄漏:@AfterReturning(value = "@annotation(controllerLog)")public void clearThreadLocal() { TIME_THREADLOCAL.remove();}
Controller方法
@ControllerLog(operation = "查询用户列表")@GetMapping("/list")public List<User> list() { // 业务逻辑}AOP切面逻辑
@Aspect@Componentpublic class LogAspect { private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<>(); @Before("@annotation(controllerLog)") public void doBefore(JoinPoint joinPoint, ControllerLog controllerLog) { TIME_THREADLOCAL.set(System.currentTimeMillis()); // 可记录请求参数、类名、方法名等 } @After("@annotation(controllerLog)") public void doAfter(JoinPoint joinPoint, ControllerLog controllerLog) { long costTime = System.currentTimeMillis() - TIME_THREADLOCAL.get(); System.out.println("方法" + joinPoint.getSignature() + "执行耗时:" + costTime + "ms"); TIME_THREADLOCAL.remove(); }}这段代码通过AOP实现了非侵入式的日志时间统计,核心步骤为:
优势在于解耦日志逻辑与业务代码,且支持通过注解属性灵活配置日志行为(如操作类型、模块名等)。