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
——此记
____________________________特此,勉励____________________________
本文作者:cheng2839
本文链接:https://www.cnblogs.com/cheng2839
关于博主:评论和私信会在第一时间回复。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/cheng2839
关于博主:评论和私信会在第一时间回复。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!