Spring Aop
好久没碰Aop,最近有个需求,类似收集请求参数的,记录下来做个简单的记录。
大致可以理解成:
有一些方法的请求参数记录下来
有些参数在返回参数记录
异常信息也要记录
获取请求参数
然后我就想到,项目中的JWTHandlerInterceptor这个类里面有进行了jwt的解析,可以通过解析出来,放进HttpServletRequest里面,这样通过GetAttribute就可以拿到clientId了。
LegacyUser这个参数,可以通过@log的注解,作用在方法上,然后在AOP去拿到这个参数,然后再存起来
get ClientId: 通过springMVC的方法去拿HttpServletRequest
1 2
| HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String clientId = (String) request.getAttribute(CommonConstant.CLIENTID);
|
请求参数是一个对象的,获取其中某个字段的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private DocumentAuditInfoDTO getParamValue(ProceedingJoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Object[] args = joinPoint.getArgs();
DocumentAuditInfoDTO documentPo = new DocumentAuditInfoDTO();
for (Object arg : args) { if (arg instanceof MultipartFile) { documentPo.setFileSize(((MultipartFile) arg).getSize()); } if (arg instanceof DocumentInfoDto) { documentPo.setDocType(((DocumentInfoDto) arg).getDocType()); documentPo.setDocSubType(((DocumentInfoDto) arg).getDocSubType()); } } return documentPo; }
|
获取异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Around("@annotation(com.fwk.ecm.documentprocessor.aop.AuditLog)") public Object doAuditLog(ProceedingJoinPoint joinPoint) throws Throwable { log.debug("do Auditlog"); LocalDateTime startTime = LocalDateTime.now(); Object result = null; String errorMsg = null; DocumentDo documentDo = new DocumentDo();
try { result = joinPoint.proceed(); return result; } catch (Exception ex) { errorMsg = truncateErrorMessage(buildCausedByExceptionInline(ex)); log.error("Method [{}] failed: {}", joinPoint.getSignature().getName(), errorMsg, ex); throw ex; } finally {}
|
获取返回参数
在finally里面获取到joinPoint的result的类型,然后转换成自己想要的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| finally { try { LocalDateTime endTime = LocalDateTime.now(); long executionTime = ChronoUnit.MILLIS.between(startTime, endTime);
buildAuditData(joinPoint, startTime, endTime, executionTime, errorMsg, result, documentDo); CompletableFuture.runAsync(() -> auditLogEventProcessor.sendAuditLogEvent(createAuditEvent(documentDo)) .exceptionally(e -> { log.warn("Failed to send audit log: {}", e.getMessage()); return null; }); } catch (Exception e) { log.error("Audit log processing failed: {}", e.getMessage(), e); } }
|
1 2 3
| CompletableFuture.runAsync(()->{ // 这个异步不知道提升大不大 });
|
一些知识
@around 是切入切出,既可以拿到入参,也可以拿到出参,也可以拿到异常信息,用的比较多
joinPoint.proceed():继续执行被拦截的方法,相当于放行,有返回值可以对应拿到
Object[] args = joinPoint.getArgs(); 入参的参数值
总结
做这个aop尽量避免在切面又去查询,因为有千千万万个日志(因为我做这些就是为了解决这个查询问题)
// 每天减少100万次查询,是不是听起来很牛逼
一些获取参数的方法要分清楚,要不然一不小心就空指针