SpringAop做一些增强

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();
//value
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万次查询,是不是听起来很牛逼

一些获取参数的方法要分清楚,要不然一不小心就空指针


SpringAop做一些增强
https://liu-cj25.github.io/2025/08/14/SpringAop做一些增强/
Author
cj
Posted on
August 14, 2025
Licensed under