看到同事在业务方法底部打印了日志,不禁想到了切面打印日志。于是动手测试了一把。
这是同事在业务方法结尾加的打印日志。而且不止这一个方法有,其他方法都有。
log.info("车辆故障列表返回完毕。");
想到了切面,@Aspect,这个东西整体打印日志,不好么?于是上手测试了一番。虽然说代码都是一步一步优化来的, 我在这只贴最终版本。
首先定义两个对象,记录日志信息。
@Data
public class RequestInfo {
private String ip;
private String url;
private String httpMethod;
private String classMethod;
private Object requestParams;
private Object result;
private Long timeCost;
}
@Data
public class RequestErrorInfo {
private String ip;
private String url;
private String httpMethod;
private String classMethod;
private Object requestParams;
private RuntimeException exception;
}
然后定义具体的切面
切入点,切入点支持表达式,也支持具体的注解。
@Pointcut("execution(* com.sanning.exercise2022maven.service.*.*(..))")
public void logPointCut() {
}
然后通知呢,有@Before、@After、@Around、@AfterReturning、@AfterThrowing。
我的需求就是打印方法的入参、返回结果,执行时间。所以直接用了@Around代替@Before、@After。
@Around("logPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String className = joinPoint.getTarget().getClass().getName();
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
String methodName = signature.getMethod().getName();
long beginTime = System.currentTimeMillis();
//执行方法
Object result = joinPoint.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
String params = "";
//请求的参数
Object[] args = joinPoint.getArgs();
try{
if (args.length==1){
params = JSONObject.toJSONString(args[0]);
}else{
params = JSONObject.toJSONString(args);
}
}catch (Exception e){
}
RequestInfo requestInfo = new RequestInfo();
requestInfo.setIp(request.getRemoteAddr());
requestInfo.setUrl(request.getRequestURL().toString());
requestInfo.setHttpMethod(methodName);
requestInfo.setClassMethod(className);
requestInfo.setRequestParams(params);
requestInfo.setResult(result);
requestInfo.setTimeCost(time);
log.info("Request Info : {}", JSONObject.toJSONString(requestInfo));
return result;
}
另外也测试了@AfterThrowing,不过目前不确定是否有用。先放到这里。
@AfterThrowing(pointcut = "logPointCut()", throwing = "e")
public void afterThrow(JoinPoint joinPoint, RuntimeException e){
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
String params = "";
//请求的参数
Object[] args = joinPoint.getArgs();
if (args.length==1){
params = JSONObject.toJSONString(args[0]);
}else{
params = JSONObject.toJSONString(args);
}
RequestErrorInfo requestErrorInfo = new RequestErrorInfo();
requestErrorInfo.setIp(request.getRemoteAddr());
requestErrorInfo.setIp(request.getRemoteAddr());
requestErrorInfo.setUrl(request.getRequestURL().toString());
requestErrorInfo.setHttpMethod(signature.getMethod().getName());
requestErrorInfo.setClassMethod(signature.getDeclaringTypeName());
requestErrorInfo.setRequestParams(params);
requestErrorInfo.setException(e);
log.info("RequestErrorInfo.....{}", JSONObject.toJSON(requestErrorInfo));
}
补充:
- json用的alibaba的fastjson,请自行引入。