Spring Aspect编程中,Spring切面包含通知和切点,通知和切点分别定义了在何时何处执行切面逻辑。
其中,Spring定义了五种不同类型的通知:
- Before(目标方法执行前)
- After(目标方法执行后,不关注执行结果)
- After-returning(目标方法执行后,返回通知)
- After-throwing(目标方法抛出异常后)
- Around(目标方法执行前后、异常)
Spring切点,通过匹配规则查找合适的连接点,AOP会在这些连接点上织入通知
本文仅关注@Around,通过切面逻辑并在其中添加Log或其他方式,帮助我们快速定位异常点,方便系统监控和bug排查,并通过下方代码展示其使用方式
@Aspect
@Component
@Slf4j
public class ControllerLogAop {
@Pointcut("execution(* *..*.*.controller..*.*(..))")
public void controller() {
}
@Around("controller()")
public Object controller(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 获取类名
String className = proceedingJoinPoint.getTarget().getClass().getSimpleName();
// 获取方法名
String methodName = proceedingJoinPoint.getSignature().getName();
// 获取方法的参数
Object[] args = proceedingJoinPoint.getArgs();
// 获取controller的请求属性数据
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = Objects.requireNonNull(requestAttributes).getRequest();
printRequestLog(request, className, methodName, args);
long start = System.currentTimeMillis();
// 继续执行方法逻辑
Object returnObj = proceedingJoinPoint.proceed();
printResponseLog(request, className, methodName, returnObj, System.currentTimeMillis() - start);
return returnObj;
}
private void printRequestLog(HttpServletRequest request, String clazzName, String methodName, Object[] args) throws JsonProcessingException {
log.debug("Request URL: [{}], URI: [{}], Request Method: [{}], IP: [{}]",
request.getRequestURL(),
request.getRequestURI(),
request.getMethod(),
ServletUtil.getClientIP(request));
if (args == null || !log.isDebugEnabled()) {
return;
}
boolean shouldNotLog = false;
for (Object arg : args) {
if (arg == null ||
arg instanceof HttpServletRequest ||
arg instanceof HttpServletResponse ||
arg instanceof MultipartFile ||
arg.getClass().isAssignableFrom(MultipartFile[].class)) {
shouldNotLog = true;
break;
}
}
if (!shouldNotLog) {
String requestBody = JsonUtils.objectToJson(args);
log.debug("{}.{} Parameters: [{}]", clazzName, methodName, requestBody);
}
}
private void printResponseLog(HttpServletRequest request, String className, String methodName, Object returnObj, long usage) throws JsonProcessingException {
if (log.isDebugEnabled()) {
String returningData = null;
if (returnObj != null) {
if (returnObj.getClass().isAssignableFrom(byte[].class)) {
returningData = "Binary data";
} else {
returningData = JsonUtils.objectToJson(returnObj);
}
}
log.debug("{}.{} Response: [{}], usage: [{}]ms", className, methodName, returningData, usage);
}
}
}
参考文献:
代码学习来源