选优化代码的方向,方法入参和返回结果日志首当其冲,每个方法都会有这两个日志,一大堆冗余的代码,而且什么样的打印格式都有,非常的杂乱。
`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 地址:github.com/chengxy-nds/Springboot-…
————————————————
原文作者:chengxy-nds
转自链接:https://learnku.com/articles/47427
版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请保留以上作者信息和原文链接。