前言:
本次主要是提供了两种打印日志的方式,可供大家挑选
1.基于注解:
优点:
灵活
缺点:
工作量大,需要在每一个需要打印的地方加上注解,并且配置比较繁琐
代码:
/*** 切点配置类*/@Slf4j@Aspect@Component@EnableAspectJAutoProxypublic class AopConfig {/*** 方法用途(切入点表达式可以用&&,||,!来组合使用):*execution: 匹配连接点:execution(* com.example.demo.*(..))--com.example.demo包下所有类的方法*within: 某个类里面*this: 指定AOP代理类的类型*target:指定目标对象的类型*args: 指定参数的类型*bean:指定特定的bean名称,可以使用通配符(Spring自带的)*@target: 带有指定注解的类型*@args: 指定运行时传的参数带有指定的注解*@within: 匹配使用指定注解的类*@annotation:指定方法所应用的注解* <br/>* 操作步骤: TODO<br/>* ${tags}*/@Pointcut("@annotation(com.deve.config.annotation.WinControllerPointCut)")public void winPointCut() {}/*** 前置通知* 方法用途:*在winPointCut注解之前执行*标识一个前置增强方法,相当于BeforeAdvice的功能.* <br/>* 操作步骤: TODO<br/>* ${tags}*/@Async//异步注解@Before("winPointCut()")public void beforeCall(JoinPoint joinPoint) {log.info("日志记录开始-------------");//前置通知-业务,入参需要切点方法定义好ServletRequestAttributes attributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();log.info("before-接口路径:{}", request.getRequestURL().toString());log.info("before-请求方式:{}", request.getMethod());log.info("before-类方法:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());log.info("before-请求参数:" + Arrays.toString(joinPoint.getArgs()));}/*** 返回通知* 方法用途:*在winPointCut注解之后执行*final增强,不管是抛出异常或者正常退出都会执行。* @AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.* @AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.* <br/>* 操作步骤: TODO<br/>* ${tags}*/@Async//异步注解@AfterReturning(pointcut = "winPointCut()", returning = "resp")public void returnCall(Object resp) {//后置通知-业务,入参需要切点方法定义好ServletRequestAttributes attributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();log.info("接口路径:{}", request.getRequestURL().toString());log.info("Result:{}", JSON.toJSONString(resp));}/*** 异常通知* @param jp* @param ex*/@Async//异步注解@AfterThrowing(throwing = "ex", pointcut = "winPointCut()")public void throwsCall(JoinPoint jp,Exception ex){log.error("产生异常的方法:{}"+jp);log.error("异常种类:{}"+ex);}/*** 后置通知* @param jp*/@Async//异步注解@After("winPointCut()")public void afterCall(JoinPoint jp){log.info("日志记录结束-------------");}/*** 环绕通知* 方法用途:*@Around 环绕增强,相当于MethodInterceptor,对带@winPointCut注解的方法进行切面,并获取到注解的属性值*ProceedingJoinPoint: 环绕通知* <br/>* 操作步骤: TODO<br/>* ${tags}*/@Async //异步注解//@Around("winPointCut() && @annotation(winControllerPointCut)")public Object aroundCall(ProceedingJoinPoint joinPoint, WinControllerPointCut winControllerPointCut) throws Throwable {Object obj = null;try {// winPointCut注解的属性值winControllerPointCut.remark();Object[] args = joinPoint.getArgs();String arg = JSON.toJSONString(args);log.info("请求参数:{}"+ arg);Signature signature = joinPoint.getSignature();// 方法package路径String methodUrl = signature.getDeclaringTypeName();// 方法名,不包含package路径String method = signature.getName();log.info("正在执行:{}" + method + "方法,路径:{}" + methodUrl);// obj是返回的结果,joinPoint.proceed用于启动目标方法执行,非常重要obj = joinPoint.proceed(args);} catch (Throwable throwable) {throwable.printStackTrace();}return obj;}}/*** 接口切点自定义注解,用于捕捉个别方法运行时详细情况*/@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Documentedpublic @interface WinControllerPointCut {/*** 操作名称* @return*/String remark() default "";/*** 操作类型* @return*/String type() default "QUERY";}
2.基于工具类
优点:
配置简单,操作方便
缺点:
会打印每一个方法,消耗比较大
代码:
/*** 切点日志打印工具类* 打印所有请求的 url 、方法 、 参数*/@Aspect@Component@Slf4jpublic class LogAspectUtils {/** 以 controller 包 的所有请求 为 切入点 */@Pointcut("execution(* com.deve.controller..*.*(..))")public void pointCat() {}/** 切点之前 */@Before("pointCat()")public void doBefore(JoinPoint joinPoint) {//获取request对象HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();log.info("========================================== Start");log.info("请求地址 :{}", request.getRequestURL().toString());log.info("请求路径 :{}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());log.info("请求参数 :{}", JSON.toJSONString(joinPoint.getArgs()));}/*** 切点之后*/@After("pointCat()")public void doAfter() {log.info("");}/*** 环绕*/@Around("pointCat()")public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {long startTime = System.currentTimeMillis();log.info("开始时间 :{}", startTime);Object result = proceedingJoinPoint.proceed();log.info("返回参数 :{}", JSON.toJSONString(result).length()>=1000?"参数太大不打印了":JSON.toJSONString(result));long endTime = System.currentTimeMillis();log.info("结束时间 :{}", endTime);log.info("========================================== 执行耗时 :{} ms", endTime - startTime);return result;}}