天天看点

Spring Aspect编程中@Around注解的使用及接口Controller监控

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);
        }
    }
}
           

参考文献:

代码学习来源