Aop 日志切面,打印日志
1 日志打印用来监控程序的执行很重要
手动在Controller 里面打印日志很繁琐。
package com.mangoubiubiu.controller; import com.alibaba.fastjson.JSONObject; import com.mangoubiubiu.utils.R; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; @RestController @Slf4j public class LoginController { @PostMapping("login") public R login(@RequestBody JSONObject jsonObject, HttpServletRequest request){ log.info("Thread name is {} Invoke api url is {} in params is {}",Thread.currentThread().getName(),request.getRequestURL(),jsonObject.toJSONString()); //----业务代码 调用service log.info("Thread name is {} Invoke api url is {} out params is {}",Thread.currentThread().getName(),request.getRequestURL(),R.ok().data(jsonObject)); return R.ok().data(jsonObject); } }
虽然也能打印到,但是有一万个 方法 就复制黏贴二万条 那多多少少有点拉胯,而且不易维护。
二 进阶,利用Aop进行切面,进行日志打印
package com.mangoubiubiu.aspect; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; /** * 日志切面类 */ @Aspect @Component @Slf4j public class LogAspect { /** * 切入点 */ @Pointcut("execution(public * com.mangoubiubiu.controller.*.*(..))") public void pointCut(){} /** * 前置通知 在目标方法 运行前执行 * @param joinpoint */ @Before("pointCut()") public void logStart(JoinPoint joinpoint){ HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); String requestURL = request.getRequestURL().toString(); //获取入参信息 Object[] args= joinpoint.getArgs(); log.info("Thread name is {} Invoke api url is {} in params is {}",Thread.currentThread().getName(),requestURL,Arrays.asList(args)); } /** * 返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后执行 * @param joinpoint * @param result */ //JoinPoint 一定要出现在参数表的第一位 @AfterReturning(value="pointCut()",returning="result") public void logreturn(JoinPoint joinpoint,Object result){ HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); String requestURL = request.getRequestURL().toString(); log.info("Thread name is {} Invoke api url is {} out params is {}",Thread.currentThread().getName(),requestURL,result); } }
测试
2021-12-10 22:04:38.530 INFO 9816 --- [io-10090-exec-1] com.mangoubiubiu.aspect.LogAspect : Thread name is http-nio-10090-exec-1 Invoke api url is http://127.0.0.1:10090/login_by_session/login in params is [{"mayr":"你看后"}, org.apache.catalina.connector.RequestFacade@6eaba842] 2021-12-10 22:04:38.594 INFO 9816 --- [io-10090-exec-1] com.mangoubiubiu.aspect.LogAspect : Thread name is http-nio-10090-exec-1 Invoke api url is http://127.0.0.1:10090/login_by_session/login out params is R(success=true, code=20000, message=成功, data={"mayr":"你看后"})
非常nice
二 再次进阶,如果我想计算接口调用耗时 怎么做---利用环绕通知(永远滴神)
package com.mangoubiubiu.aspect; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import sun.rmi.transport.ObjectTable; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; /** * 日志切面类 */ @Aspect @Component @Slf4j public class LogAspect { /** * 切入点 */ @Pointcut("execution(public * com.mangoubiubiu.controller.*.*(..))") public void pointCut(){} /** * 前置通知 在目标方法 运行前执行 * @param joinpoint */ //@Before("pointCut()") public void logStart(JoinPoint joinpoint){ HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); String requestURL = request.getRequestURL().toString(); //获取入参信息 Object[] args= joinpoint.getArgs(); log.info("Thread name is {} Invoke api url is {} in params is {}",Thread.currentThread().getName(),requestURL,Arrays.asList(args)); } /** * 返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后执行 * @param joinpoint * @param result */ //JoinPoint 一定要出现在参数表的第一位 //@AfterReturning(value="pointCut()",returning="result") public void logreturn(JoinPoint joinpoint,Object result){ HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); String requestURL = request.getRequestURL().toString(); log.info("Thread name is {} Invoke api url is {} out params is {}",Thread.currentThread().getName(),requestURL,result); } /** * 环绕通知 * @param joinPoint * @return */ @Around("pointCut()") public Object around(ProceedingJoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); String requestURL = request.getRequestURL().toString(); Object[] args= joinPoint.getArgs(); try { Long startTime=System.currentTimeMillis(); log.info("Thread name is {} Invoke api url is {} in params is {}",Thread.currentThread().getName(),requestURL,Arrays.asList(args)); //执行目标方法 Object result = joinPoint.proceed(); log.info("Thread name is {} Invoke api url is {} out params is {} Time-consuming {}ms",Thread.currentThread().getName(),requestURL,result,System.currentTimeMillis()-startTime); return result; }catch (Throwable e){ } return null; } }
注掉了哈
测试
非常强大
三 再次进阶,环绕通知 篡改返回参数
测试
非常强大 , 环绕通知的返回参数,就是方法的返回参数,并且能修改方法的返回参数,在实际应用场景中可以塞值,非常好用。