• 又被逼着优化代码,这次我干掉了出入参 Log日志


    本文收录在个人博客:www.chengxy-nds.top,技术资源共享。

    最近技术部突然刮起一阵 review 代码的小风,挨个项目组过代码,按理说这应该是件挺好的事,让别人指出自己代码中的不足,查缺补漏,对提升自身编码能力有很大帮助,毕竟自己审查很容易“陶醉”在自己写的代码里。
    在这里插入图片描述

    不过,代码 review 的详细程度令人发指,一行一行的分析,简直就是个培训班啊。不夸张的说,如果我村里仅有县重点小学学历的四大爷,来听上一个月后,保证能上手开发,666~

    既然组内气氛到这了,咱也得行动起来,要不哪天评审到我的代码,让人家指指点点的心里多少有点不舒服,与其被动优化代码不如主动出击~

    选优化代码的方向,方法入参和返回结果日志首当其冲,每个方法都会有这两个日志,一大堆冗余的代码,而且什么样的打印格式都有,非常的杂乱。

    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 ,用来自定义方法输出日志的描述。

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    @Documented
    public @interface PrintlnLog {
    
        /**
         * 自定义日志描述信息文案
         *
         * @return
         */
        String description() default "";
    }
    

    二、切面类

    接下来编写@PrintlnLog 注解对应的切面实现,doBefore()中输出方法的自定义描述、入参、请求方式、请求url、被调用方法的位置等信息,doAround() 中打印方法返回结果。

    注意: 如何想指定切面在哪个环境执行,可以用@Profile 注解,只打印某个环境的日志。

    @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注解,并添加自定义方法描述。

    @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

    原创不易,燃烧秀发输出内容,如果有一丢丢收获,点个赞鼓励一下吧!

    整理了几百本各类技术电子书,送给小伙伴们。关注公号回复【666】自行领取。和一些小伙伴们建了一个技术交流群,一起探讨技术、分享技术资料,旨在共同学习进步,如果感兴趣就加入我们吧!

  • 相关阅读:
    VirtualBox Win7 虚拟机 共享文件夹设置
    图像的 SNR 和 PSNR 的计算
    swprintf %s %ws %S 的区别
    解决 Virtual Box 启动 Cannot load R0 module supLoadModule returned VERR_LDR_MISMATCH_NATIVE Failed to register ourselves as a PCI Bus (VERR_MODULE_NOT_FOUND)
    VS2015/2013/2012 IIS Express Debug Classic ASP
    Beginning Android 4 中 Demo Basic/Switch 的问题.
    【虚拟机】解决网络适配器没有 VirtualBox Host-Only Ethernet Adapter 问题
    Docker安装Tomcat镜像并部署web项目
    Docker——入门实战
    Centos7上安装docker
  • 原文地址:https://www.cnblogs.com/chengxy-nds/p/13345256.html
Copyright © 2020-2023  润新知