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);
}
}
}
參考文獻:
代碼學習來源