1. 程式人生 > >又被逼著優化程式碼,這次我幹掉了出入參 Log日誌

又被逼著優化程式碼,這次我幹掉了出入參 Log日誌

>本文收錄在個人部落格:[www.chengxy-nds.top](http://www.chengxy-nds.top),技術資源共享。 最近技術部突然颳起一陣 `review` 程式碼的小風,挨個專案組過程式碼,按理說這應該是件挺好的事,讓別人指出自己程式碼中的不足,查缺補漏,對提升自身編碼能力有很大幫助,畢竟自己審查很容易“`陶醉`”在自己寫的程式碼裡。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200720135402500.jpg?#pic_center) 不過,程式碼 `review` 的詳細程度令人髮指,一行一行的分析,簡直就是個培訓班啊。不誇張的說,如果我村裡僅有縣重點小學學歷的四大爺,來聽上一個月後,保證能上手開發,666~ 既然組內氣氛到這了,咱也得行動起來,要不哪天評審到我的程式碼,讓人家指指點點的心裡多少有點不舒服,與其被動優化程式碼不如主動出擊~ 選優化程式碼的方向,方法入參和返回結果日誌首當其衝,每個方法都會有這兩個日誌,一大堆冗餘的程式碼,而且什麼樣的列印格式都有,非常的雜亂。 ```javascript public OrderDTO getOrder(OrderVO orderVO, String name) { log.info("訂單詳情入參:orderVO={},name={}", JSON.toJSONString(orderVO), name); OrderDTO orderInfo = orderService.getOrderInfo(orderVO); log.info("訂單詳情結果:orderInfo={}", JSON.toJSONString(orderInfo)); return orderInfo; } ``` 下邊我們利用 `AOP` 實現請求方法的入參、返回結果日誌統一列印,避免日誌列印格式雜亂,同時減少業務程式碼量。 ### 一、自定義註解 自定義切面註解`@PrintlnLog` 用來輸出日誌,註解許可權 `@Target({ElementType.METHOD})` 限制只在方法上使用,註解中只有一個引數 `description` ,用來自定義方法輸出日誌的描述。 ```javascript @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface PrintlnLog { /** * 自定義日誌描述資訊文案 * * @return */ String description() default ""; } ``` ### 二、切面類 接下來編寫`@PrintlnLog` 註解對應的切面實現,`doBefore()`中輸出方法的自定義描述、入參、請求方式、請求url、被呼叫方法的位置等資訊,`doAround()` 中列印方法返回結果。 `注意:` 如何想指定切面在哪個環境執行,可以用`@Profile` 註解,只打印某個環境的日誌。 ```javascript @Slf4j @Aspect @Component //@Profile({"dev"}) //只對某個環境列印日誌 public class LogAspect { private static final String LINE_SEPARATOR = System.lineSeparator(); /** * 以自定義 @PrintlnLog 註解作為切面入口 */ @Pointcut("@annotation(com.chengxy.unifiedlog.config.PrintlnLog)") public void PrintlnLog() { } /** * @param joinPoint * @author fu * @description 切面方法入參日誌列印 * @date 2020/7/15 10:30 */ @Before("PrintlnLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String methodDetailDescription = this.getAspectMethodLogDescJP(joinPoint); log.info("------------------------------- start --------------------------"); /** * 列印自定義方法描述 */ log.info("Method detail Description: {}", methodDetailDescription); /** * 列印請求入參 */ log.info("Request Args: {}", JSON.toJSONString(joinPoint.getArgs())); /** * 列印請求方式 */ log.info("Request method: {}", request.getMethod()); /** * 列印請求 url */ log.info("Request URL: {}", request.getRequestURL().toString()); /** * 列印呼叫方法全路徑以及執行方法 */ log.info("Request Class and Method: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); } /** * @param proceedingJoinPoint * @author xiaofu * @description 切面方法返回結果日誌列印 * @date 2020/7/15 10:32 */ @Around("PrintlnLog()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { String aspectMethodLogDescPJ = getAspectMethodLogDescPJ(proceedingJoinPoint); long startTime = System.currentTimeMillis(); Object result = proceedingJoinPoint.proceed(); /** * 輸出結果 */ log.info("{},Response result : {}", aspectMethodLogDescPJ, JSON.toJSONString(result)); /** * 方法執行耗時 */ log.info("Time Consuming: {} ms", System.currentTimeMillis() - startTime); return result; } /** * @author xiaofu * @description 切面方法執行後執行 * @date 2020/7/15 10:31 */ @After("PrintlnLog()") public void doAfter(JoinPoint joinPoint) throws Throwable { log.info("------------------------------- End --------------------------" + LINE_SEPARATOR); } /** * @param joinPoint * @author xiaofu * @description @PrintlnLog 註解作用的切面方法詳細細資訊 * @date 2020/7/15 10:34 */ public String getAspectMethodLogDescJP(JoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); return getAspectMethodLogDesc(targetName, methodName, arguments); } /** * @param proceedingJoinPoint * @author xiaofu * @description @PrintlnLog 註解作用的切面方法詳細細資訊 * @date 2020/7/15 10:34 */ public String getAspectMethodLogDescPJ(ProceedingJoinPoint proceedingJoinPoint) throws Exception { String targetName = proceedingJoinPoint.getTarget().getClass().getName(); String methodName = proceedingJoinPoint.getSignature().getName(); Object[] arguments = proceedingJoinPoint.getArgs(); return getAspectMethodLogDesc(targetName, methodName, arguments); } /** * @param targetName * @param methodName * @param arguments * @author xiaofu * @description 自定義註解引數 * @date 2020/7/15 11:51 */ public String getAspectMethodLogDesc(String targetName, String methodName, Object[] arguments) throws Exception { Class targetClass = Class.forName(targetName); Method[] methods = targetClass.getMethods(); StringBuilder description = new StringBuilder(""); for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { description.append(method.getAnnotation(PrintlnLog.class).description()); break; } } } return description.toString(); } } ``` ### 三、應用 我們在需要列印入參和返回結果日誌的方法,加上`@PrintlnLog`註解,並新增自定義方法描述。 ```javascript @RestController @RequestMapping public class OrderController { @Autowired private OrderService orderService; @PrintlnLog(description = "訂單詳情Controller") @RequestMapping("/order") public OrderDTO getOrder(OrderVO orderVO, String name) { OrderDTO orderInfo = orderService.getOrderInfo(orderVO); return orderInfo; } } ``` 程式碼裡去掉 `log.info`日誌列印,加上 `@PrintlnLog` 看一下效果,清晰明瞭。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200720141940682.png?) Demo `GitHub`地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-aop-unifiedlog **原創不易,燃燒秀髮輸出內容,如果有一丟丟收穫,點個贊鼓勵一下吧!** 整理了幾百本各類技術電子書,送給小夥伴們。關注公號回覆【666】自行領取。和一些小夥伴們建了一個技術交流群,一起探討技術、分享技術資料,旨在共同學習進步,如果感興趣就加入我們吧! ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91c2VyLWdvbGQtY2RuLnhpdHUuaW8vMjAyMC8yLzQvMTcwMGU0Mjk1MDQzMjQ0Yg?x-oss-process=image/form