大家好我是小羽,最近正在准备秋招,总结一下AOP实现日志的功能的具体写法。
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.创建自定义注解
package com.ljh.springaop.utils;
import java.lang.annotation.*;
/**
* @author shenyi
* @data 2022/10/8
* @apiNote
*/
@Target({ElementType.METHOD}) //用于描述方法
@Retention(RetentionPolicy.RUNTIME) //注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented //javadoc 文档是否显示
public @interface Log {
//模块
String value() default "";
//功能
String action() default "";
}
3.创建AOP配置类
package com.ljh.springaop.controller;
import com.ljh.springaop.utils.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author shenyi
* @data 2022/10/8
* @apiNote AOP日志
*/
@Aspect //标记该类是AOP实现类
@Component(value = "logAspect")
public class AOPAspect {
//配置切入点
//com.ljh.springaop.utils.Log为自定义注解路径
@Pointcut("@annotation(com.ljh.springaop.utils.Log)")
public void logPointCut(){
}
//配置前置通知,在方法执行前执行该方法
@Before("logPointCut()")
public void before(JoinPoint joinPoint) throws Exception {
System.out.println("执行前置通知...");
//获取注解名称
System.out.println("获取方法的名称"+joinPoint.getSignature().getName());
Log controllerLog=getAnnotationLog(joinPoint);
System.out.println("获取注解的名称"+controllerLog.action());
System.out.println("获取注解的属性"+controllerLog.value());
}
@AfterReturning("logPointCut()")
public void after(){
System.out.println("执行后置通知...");
}
//获取注解
private static Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
}
4.创建Controller控制类
package com.ljh.springaop.controller;
import com.ljh.springaop.utils.Log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author shenyi
* @data 2022/10/8
* @apiNote
*/
@RestController
@RequestMapping("/login")
public class Login {
@GetMapping("/a")
@Log(value = "模块名称",action = "模块行为")
public void hello(){
System.out.println("hello word");
}
}
最后的执行结果
项目的目录结构
5.切面类注解
其实切面类注解有很多,下面给大家列出常用的切面类注解。
@Aspect 声明切面,修饰切面类,从而获得 通知。
@Before 前置通知,在目标方法开始之前执行
@AfterReturning 后置通知
@Around 环绕 这个注解我不经常用,有一些坑,详情请自行搜索。
其实我们仅使用环绕通知就可以实现前置通知、后置通知、异常通知、最终通知等的效果。
@AfterThrowing 抛出异常
@After 最终
@PointCut ,切入点,修饰方法 private void xxx(){} 之后通过“方法名”获得切入点引用