AOP日志拦截器

各位读者,大家好!

     我们在开发项目时,要经常输出大量的日志,以便问题的排查。但是写日志又显得特别繁琐,特别是固定的日志内容。

     比如,接口开发时,经常要打印出【入参】、【响应结果】及【异常日志】,那么有没有办法统一管理这些日志呢,答案是可以的。

    下面我们就运用Spring的AOP技术来实现它,我们这里用到了Before(前置通知)、After(后置通知)及Throwable(异常通知)。

   

    思路:要想对不同的方法打印各自的日志,那么就需要开发者提供这个方法的使用说明,在这里我们就自定义一个注解MyLogAdvice,其作用是用于标注需要被日志拦截器管理的方法,及该方法的说明。如下:

 

 

 1 package com.cheng2839.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /**
10  * 日志打印
11  * @author cheng2839
12  * @date 2018年11月16日
13  */
14 @Retention(RetentionPolicy.RUNTIME)
15 @Target(ElementType.METHOD)
16 @Documented
17 public @interface CustomLogAdvice {
18 
19     //方法作用
20     String msg();
21 
22 }

 

 

    接下来,我们开发日志拦截器LogAdvice

  1 package com.cheng2839.interceptor;
  2 
  3 import com.cheng2839.annotation.MyLogAdvice;
  4 import org.aspectj.lang.JoinPoint;
  5 import org.aspectj.lang.Signature;
  6 import org.aspectj.lang.annotation.AfterReturning;
  7 import org.aspectj.lang.annotation.AfterThrowing;
  8 import org.aspectj.lang.annotation.Aspect;
  9 import org.aspectj.lang.annotation.Before;
 10 import org.aspectj.lang.annotation.Pointcut;
 11 import org.aspectj.lang.reflect.MethodSignature;
 12 import org.slf4j.Logger;
 13 import org.slf4j.LoggerFactory;
 14 import org.springframework.stereotype.Component;
 15 
 16 import java.io.PrintWriter;
 17 import java.io.StringWriter;
 18 import java.lang.reflect.Method;
 19 
 20 /**
 21  * 日志AOP拦截
 22  * @author cheng2839
 23  * @date 2018年11月16日
 24  */
 25 @Aspect
 26 @Component
 27 public class LogAdvice {
 28 
 29     private Logger logger = LoggerFactory.getLogger(this.getClass());
 30 
 31     @Pointcut("execution(@(@com.cheng2839.annotation.MyLogAdvice *) * *(..)) " +
 32             "|| execution(@com.cheng2839.annotation.MyLogAdvice * *(..)) " +
 33             "|| execution(@(@com.cheng2839.annotation.MyLogAdvice *) * *(..))")
 34     public void log() {}
 35 
 36     /**
 37      * 前置 - 入参打印
 38      * @param joinPoint
 39      * @author cheng2839
 40      * @date 2018年11月16日
 41      */
 42     @Before("log()")
 43     public void beforeAspect(JoinPoint joinPoint) {
 44         try {
 45             StringBuilder methodMsg = getMethodMsg(joinPoint);
 46             if (ObjectUtil.isNotNullOrNotEmpty(methodMsg)) {
 47                 Object[] args = joinPoint.getArgs();
 48                 StringBuilder paramToString = new StringBuilder();
 49                 if (args!=null) {
 50                     for (Object p : args) {
 51                         paramToString.append(p);
 52                         paramToString.append(' ');
 53                     }
 54                 }
 55                 logger.info("{}入参:{}", methodMsg.toString(), paramToString.toString());
 56             }
 57         } catch (Exception ex) {
 58             logger.error("LogAdvice.beforeAspect exception:{}", ex);
 59         }
 60 
 61     }
 62 
 63     /**
 64      * 后置通知 - 响应结果打印
 65      * @param joinPoint
 66      * @param result
 67      * @throws Throwable
 68      * @author cheng2839
 69      * @date 2018年11月16日
 70      */
 71     @AfterReturning(pointcut = "log()", returning = "result")
 72     public void afterAspect(JoinPoint joinPoint, Object result) {
 73         try {
 74             StringBuilder methodMsg = getMethodMsg(joinPoint);
 75             if (ObjectUtil.isNotNullOrNotEmpty(methodMsg)) {
 76                 logger.info("{}响应结果:{}", methodMsg.toString(), result);
 77             }
 78         } catch (Exception ex) {
 79             logger.error("LogAdvice.afterAspect exception:{}", ex);
 80         }
 81     }
 82 
 83     /**
 84      * 异常捕获 - 异常打印
 85      * @param joinPoint
 86      * @author cheng2839
 87      * @date 2018年11月16日
 88      */
 89     @AfterThrowing(value = "log()", throwing = "e")
 90     public void throwAspect(JoinPoint joinPoint, Exception e) {
 91         try {
 92             StringBuilder methodMsg = getMethodMsg(joinPoint);
 93             if (ObjectUtil.isNotNullOrNotEmpty(methodMsg)) {
 94                 StringWriter sw = new StringWriter();
 95                 e.printStackTrace(new PrintWriter(sw));
 96                 logger.error("{}异常:{}", methodMsg.toString(), sw.toString());
 97             }
 98         } catch (Exception ex) {
 99             logger.error("LogAdvice.throwAspect exception:{}", ex);
100         }
101     }
102 
103     /**
104      * 组装方法提示消息
105      * @param joinPoint
106      * @return
107      * @author cheng2839
108      * @date 2018年11月16日
109      */
110     private StringBuilder getMethodMsg(JoinPoint joinPoint) {
111         Signature signature = joinPoint.getSignature();
112         Method method = ((MethodSignature) signature).getMethod();
113         MyLogAdvice myLogAdvice = method.getAnnotation(MyLogAdvice.class);
114 
115         StringBuilder methodMsg = null;
116         if (myLogAdvice != null) {
117             methodMsg = new StringBuilder();
118             methodMsg.append(method.getDeclaringClass().getName()); //class name
119             methodMsg.append('.');
120             methodMsg.append(method.getName()); //method name
121             methodMsg.append(' ');
122             methodMsg.append('-');
123             methodMsg.append(' ');
124             methodMsg.append(myLogAdvice.msg()); //method remark
125         }
126         return methodMsg;
127     }
128 }

 

    接下来,我们写个测试接口测试一下:

    注意:这里我创建了一个springBoot服务,端口:8392,服务的创建不再这里赘述。

 1 package com.cheng2839.controller;
 2 
 3 import com.cheng2839.annotation.MyLogAdvice;
 4 import org.springframework.web.bind.annotation.GetMapping;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RequestParam;
 7 import org.springframework.web.bind.annotation.RestController;
 8 
 9 /**
10  * 日志拦截器测试类
11  * @author cheng2839
12  * @date 2018年11月16日
13  */
14 @RestController
15 @RequestMapping("/test")
16 public class TestLogAspectController {
17 
18     @MyLogAdvice(msg = "测试日志拦截器")
19     @GetMapping(value = "/testLogAspect")
20     public String testLogAspect(@RequestParam("name") String param) {
21         return "hello,spring aop";
22     }
23 
24 }

 

   在postman或者浏览器地址栏中用GET请求访问:http://127.0.0.1:8392/test/testLogAspect?name=cheng2839

 

 

    日志输出结果如下:

1 2018-11-16 17:21:09.130 [http-nio-8392-exec-3] [INFO] com.cheng2839.interceptor.LogAdvice:com.cheng2839.controller.TestLogAspectController.testLogAspect - 测试日志拦截器入参:cheng2839 
2 2018-11-16 17:21:09.132 [http-nio-8392-exec-3] [INFO] com.cheng2839.interceptor.LogAdvice:com.cheng2839.controller.TestLogAspectController.testLogAspect - 测试日志拦截器响应结果:hello,spring aop

 

                                      ——此记

 

posted @ 2020-04-01 17:35  温柔的星空,让你感动  阅读(863)  评论(0编辑  收藏  举报