又被逼著優(yōu)化代碼,這次我干掉了出入?yún)?Log日志
本文轉(zhuǎn)載自微信公眾號(hào)「程序員內(nèi)點(diǎn)事」,作者程序員內(nèi)點(diǎn)事。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序員內(nèi)點(diǎn)事公眾號(hào)。
最近技術(shù)部突然刮起一陣 review 代碼的小風(fēng),挨個(gè)項(xiàng)目組過代碼,按理說這應(yīng)該是件挺好的事,讓別人指出自己代碼中的不足,查缺補(bǔ)漏,對(duì)提升自身編碼能力有很大幫助,畢竟自己審查很容易“陶醉”在自己寫的代碼里。
不過,代碼 review 的詳細(xì)程度令人發(fā)指,一行一行的分析,簡(jiǎn)直就是個(gè)培訓(xùn)班啊。不夸張的說,如果我村里僅有縣重點(diǎn)小學(xué)學(xué)歷的四大爺,來(lái)聽上一個(gè)月后,保證能上手開發(fā),666~
既然組內(nèi)氣氛到這了,咱也得行動(dòng)起來(lái),要不哪天評(píng)審到我的代碼,讓人家指指點(diǎn)點(diǎn)的心里多少有點(diǎn)不舒服,與其被動(dòng)優(yōu)化代碼不如主動(dòng)出擊~
選優(yōu)化代碼的方向,方法入?yún)⒑头祷亟Y(jié)果日志首當(dāng)其沖,每個(gè)方法都會(huì)有這兩個(gè)日志,一大堆冗余的代碼,而且什么樣的打印格式都有,非常的雜亂。
- public OrderDTO getOrder(OrderVO orderVO, String name) {
- log.info("訂單詳情入?yún)ⅲ簅rderVO={},name={}", JSON.toJSONString(orderVO), name);
- OrderDTO orderInfo = orderService.getOrderInfo(orderVO);
- log.info("訂單詳情結(jié)果:orderInfo={}", JSON.toJSONString(orderInfo));
- return orderInfo;
- }
下邊我們利用 AOP 實(shí)現(xiàn)請(qǐng)求方法的入?yún)?、返回結(jié)果日志統(tǒng)一打印,避免日志打印格式雜亂,同時(shí)減少業(yè)務(wù)代碼量。
一、自定義注解
自定義切面注解@PrintlnLog 用來(lái)輸出日志,注解權(quán)限 @Target({ElementType.METHOD}) 限制只在方法上使用,注解中只有一個(gè)參數(shù) description ,用來(lái)自定義方法輸出日志的描述。
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.METHOD})
- @Documented
- public @interface PrintlnLog {
- /**
- * 自定義日志描述信息文案
- *
- * @return
- */
- String description() default "";
- }
二、切面類
接下來(lái)編寫@PrintlnLog 注解對(duì)應(yīng)的切面實(shí)現(xiàn),doBefore()中輸出方法的自定義描述、入?yún)?、?qǐng)求方式、請(qǐng)求url、被調(diào)用方法的位置等信息,doAround() 中打印方法返回結(jié)果。
注意: 如何想指定切面在哪個(gè)環(huán)境執(zhí)行,可以用@Profile 注解,只打印某個(gè)環(huán)境的日志。
- @Slf4j
- @Aspect
- @Component
- //@Profile({"dev"}) //只對(duì)某個(gè)環(huán)境打印日志
- 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 切面方法入?yún)⑷罩敬蛴?nbsp;
- * @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);
- /**
- * 打印請(qǐng)求入?yún)?nbsp;
- */
- log.info("Request Args: {}", JSON.toJSONString(joinPoint.getArgs()));
- /**
- * 打印請(qǐng)求方式
- */
- log.info("Request method: {}", request.getMethod());
- /**
- * 打印請(qǐng)求 url
- */
- log.info("Request URL: {}", request.getRequestURL().toString());
- /**
- * 打印調(diào)用方法全路徑以及執(zhí)行方法
- */
- log.info("Request Class and Method: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
- }
- /**
- * @param proceedingJoinPoint
- * @author xiaofu
- * @description 切面方法返回結(jié)果日志打印
- * @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();
- /**
- * 輸出結(jié)果
- */
- log.info("{},Response result : {}", aspectMethodLogDescPJ, JSON.toJSONString(result));
- /**
- * 方法執(zhí)行耗時(shí)
- */
- log.info("Time Consuming: {} ms", System.currentTimeMillis() - startTime);
- return result;
- }
- /**
- * @author xiaofu
- * @description 切面方法執(zhí)行后執(zhí)行
- * @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 注解作用的切面方法詳細(xì)細(xì)信息
- * @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 注解作用的切面方法詳細(xì)細(xì)信息
- * @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 自定義注解參數(shù)
- * @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();
- }
- }
三、應(yīng)用
我們?cè)谛枰蛴∪雲(yún)⒑头祷亟Y(jié)果日志的方法,加上@PrintlnLog注解,并添加自定義方法描述。
- @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 看一下效果,清晰明了。
Demo GitHub地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-aop-unifiedlog