又被逼着优化代码,这次我干掉了出入参 Log日志
本文转载自微信公众号「程序员内点事」,作者程序员内点事。转载本文请联系程序员内点事公众号。
最近技术部突然刮起一阵 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

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
5G时代 运营商网络将面临何种挑战和机遇
随着国内5G的正式商用,到今天已经有一年多的时间了,期间伴随着互联网、移动化等产业趋势的不断深入发展,给传统服务提供商业务带来了全新的挑战和机遇。目前,服务提供商正处于业务转型的关键时期,而这种转型始发于市场对业务提出的新需求,最终将在服务提供商的基础设施建设与升级中得以体现。而云计算、大数据、人工智能等技术的引入正在为运营商应对5G市场所带来的种种挑战提供技术保障。 运营商网络面临的挑战 5G时代可以说给运营商网络带来了前所未有的冲击。随着5G的商业化落地,5G架构将连接亿级别的智能设备,网络流量增长会超过十倍之多,该架构需要展示强化的、更高程度的灵活性、敏捷性和自动化,这在很大程度上依赖网络功能虚拟化 (NFV) 和软件定义网络 (SDN) 基础架构,以便实现按需扩展和部署网络功能所需的弹性,支持各种全新的移动应用程序。 由于还要满足5G终端低延时、高并发等需求,5G网络采用了更加密集的微基站部署方式,而每个基站实际上就相当于一个小型或微型的数据中心,兼具计算、存储、网络等能力。越来越多的分布式数据中心无疑增加了整网系统管控和维护的复杂性,其所需的管理成本正在削弱他们的赢利能力。 ...
- 下一篇
深入理解 SecurityConfigurer 【源码篇】
松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程 我们来继续撸 Spring Security 源码。 SecurityConfigurer 在 Spring Security 中是一个非常重要的角色。在前面的文章中,松哥曾经多次提到过,Spring Security 过滤器链中的每一个过滤器,都是通过 xxxConfigurer 来进行配置的,而这些 xxxConfigurer 实际上都是 SecurityConfigurer 的实现。 所以我们今天有必要来跟大家把 SecurityConfigurer 从头到尾捋一捋。 1. SecurityConfigurer SecurityConfigurer 本身是一个接口,我们来看下: publicinterfaceSecurityConfigurer<O,BextendsSecurityBuilder<O>>{voidinit(Bbuilder)throwsException;voidconfigure(Bbuilder)thro...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS关闭SELinux安全模块
- CentOS8安装Docker,最新的服务器搭配容器使用
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池