Spring Boot自定义注解+AOP实现方法审计及问题排查
Spring Boot自定义注解AOP审计功能实现问题排查与修复
需求背景
正在开发Spring Boot应用,希望通过自定义注解实现方法审计功能,最初设计的注解为@AuditMetod,标注示例如下:
@AuditMetod(name = "SomeValue") foo() {...}
期望的最简审计逻辑为:
auditMethod(Method method) { if (method.hasAnnotation(AuditMethod.class)) { System.out.println (method.getName() + " was called at " + new Date()) } }
现存问题
确认使用Spring AOP实现该需求后,遇到两个问题:
- 切面类逻辑未触发,日志未输出预期的
----------ASPECT METHOD IS CALLED-----------内容 - 不知道如何在切面方法中获取当前拦截的目标方法对应的
Method类实例
当前已编写的代码如下:
Controller层代码
@PostMapping @LoggingRest(executor = "USER", method = "CREATE", model = "SUBSCRIPTION") public ResponseEntity<?> create(@Valid @RequestBody SubscriptionRequestDto dto) { ... }
自定义注解代码
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface LoggingRest { String executor() default "SYSTEM"; String method() default ""; String model() default ""; }
切面类代码
@Aspect @Slf4j @Component public class AuditAspect { @Pointcut(value = "@annotation(com.aspect.annotations.LoggingRest)") public void auditMethod(ProceedingJoinPoint proceedingJoinPoint) { log.info("----------ASPECT METHOD IS CALLED------------"); } }
问题修复方案
切面未触发问题修复
切面不生效的核心原因是AOP注解用法错误,同时需要确认依赖配置正确:
- 先引入Spring AOP依赖,Spring Boot项目直接引入官方starter即可:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
- 修正切点用法:
@Pointcut标注的方法仅作为切点定义标记,不能写业务逻辑,该方法返回值必须为void,不需要定义参数。 - 补充实际的增强通知(
@Around/@Before/@After等)绑定切点,编写审计逻辑。
注意:请确认@Pointcut中配置的注解全类名和你实际定义LoggingRest注解的包路径完全一致,否则切点无法匹配到目标方法
获取目标Method实例方法
在通知方法中通过JoinPoint获取方法签名,强转为MethodSignature后即可拿到对应的Method对象,同时可以直接读取注解上的配置参数。
修复后的完整切面代码
@Aspect @Slf4j @Component public class AuditAspect { // 正确定义切点:无参数、无业务逻辑,仅作为标记 @Pointcut(value = "@annotation(com.aspect.annotations.LoggingRest)") public void auditPointCut() {} // 使用环绕通知绑定切点,编写实际审计逻辑 @Around("auditPointCut()") public Object aroundAudit(ProceedingJoinPoint joinPoint) throws Throwable { log.info("----------ASPECT METHOD IS CALLED------------"); // 获取目标方法的Method实例 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method targetMethod = signature.getMethod(); // 获取方法上的注解实例,读取配置参数 LoggingRest auditAnnotation = targetMethod.getAnnotation(LoggingRest.class); String executor = auditAnnotation.executor(); String operateMethod = auditAnnotation.method(); String model = auditAnnotation.model(); // 执行原方法逻辑 Object result = joinPoint.proceed(); // 自定义审计逻辑示例 log.info("方法{}被调用,操作人:{},操作类型:{},操作模块:{},调用时间:{}", targetMethod.getName(), executor, operateMethod, model, new Date()); return result; } }
如果不需要控制原方法执行时机,仅需要在方法执行前打印审计日志,可以把
@Around替换为@Before,参数使用JoinPoint即可,不需要调用proceed()方法。
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

