SpringBoot之AOP
一、什么是AOP
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
二、目的
在不侵入代码的情况下记录请求日志,具体如下,在执行方法前记录请求路径、请求方式、请求参数等信息,在执行完成后执行数据记录。
三、必须理解的官方名称
-
切面关注点:切面关注点就是想在原来的代码上实现什么样的功能,比如在原来的代码上实现日志功能。
-
切面:切面就是一个类,这个类就是如何实现这个日志的类
-
通知:切面必须要完成的工作。即,它是类中的一个方法。
-
切入点:通知执行的 “地点”的定义。
-
连接点:与切入点匹配的执行点。
四、代码实现
@Aspect:定义这个类为日志切面类
@Pointcut:定义切入点
@execution:连接点,在什么地方执行切入
通知:
@Before:前置通知,在执行方法前执行
@AfterReturning:后置通知,在之心方法后执行
@AfterThrowing:后置异常通知,方法在执行后出现异常时执行
@Around:环绕通知,在方法前执行一次,在方法执行后在执行一次
@After:最后通知,方法执行过后执行
@Aspect//定义这个类为日志切面类
@Component
public class LoginAop {
//Pointcut定义切入点
//execution连接点
@Pointcut("execution(public * com.example.jwts.controller.*.*(..))")
public void LogAspect(){
}
//通知
@Before("LogAspect()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
StringBuffer requestURL = request.getRequestURL();
String method = request.getMethod();
String remoteAddr = request.getRemoteAddr();
Signature signature = joinPoint.getSignature();
String name = signature.getName();
log.info("请求路径:{}",requestURL);
log.info("请求方法:{}",method);
log.info("请求地址:{}",remoteAddr);
log.info("请求方法:{}",name);
Object[] args = joinPoint.getArgs();
for (Object o:args) {
log.info("请求参数:{}",o);
}
log.error("前置通知结束");
}
@After("LogAspect()")
public void doAfter(JoinPoint joinPoint){
log.info("最终通知");
}
@AfterReturning("LogAspect()")
public void doAfterReturning(JoinPoint joinPoint){
log.error("后置通知开始");
log.info("可以把日志存入数据");
}
@AfterThrowing("LogAspect()")
public void deAfterThrowing(JoinPoint joinPoint){
System.out.println("运行时异常通知");
}
@Around("LogAspect()")
public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("执行前");
joinPoint.proceed();//执行后返回的数据
System.out.println("执行后");
return joinPoint.proceed();
}
}
编写一个测试接口
@GetMapping("/login")
public void login(String name, String pass) {
log.info("执行了登录");
}
测试(前置通知,和后置通知):