• AOP 日志切面


    AOP把软件的功能模块分为两个部分:核心关注点和横切关注点。业务处理的主要功能为核心关注点,而非核心、需要拓展的功能为横切关注点。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点进行分离,使用切面有以下好处:

    • 集中处理某一关注点/横切逻辑

    • 可以很方便的添加/删除关注点

    • 侵入性少,增强代码可读性及可维护性 因此当想打印请求日志时很容易想到切面,对控制层代码0侵入

    @Aspect => 声明该类为一个注解类

    @Pointcut => 定义一个切点,可以简化代码

    • @Before => 在切点之前执行代码

    • @After => 在切点之后执行代码

    • @AfterReturning => 切点返回内容后执行代码,可以对切点的返回值进行封装

    • @AfterThrowing => 切点抛出异常后执行

    • @Around => 环绕,在切点前后执行代码

    使用@Pointcut定义切点

    @Pointcut("execution(* your_package.controller..*(..))")

    =====>@Pointcut定义了一个切点,因为是请求日志切边,因此切点定义的是Controller包下的所有类下的方法。定义切点以后在通知注解中直接使用requestServer方法名就可以了

    使用@Before再切点前执行

    ======>@Before("requestServer()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes)
    RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        LOGGER.info("===============================Start========================");
        LOGGER.info("IP                 : {}", request.getRemoteAddr());
        LOGGER.info("URL                : {}", request.getRequestURL().toString());
        LOGGER.info("HTTP Method        : {}", request.getMethod());
        LOGGER.info("Class Method       : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
    }

    使用@Around打印进入控制层的入参

    =====>@Around("requestServer()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        LOGGER.info("Request Params       : {}", getRequestParams(proceedingJoinPoint));
        LOGGER.info("Result               : {}", result);
        LOGGER.info("Time Cost            : {} ms", System.currentTimeMillis() - start);

        return result;
    }

    ========>getRquestParams方法

    private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {
         Map<String, Object> requestParams = new HashMap<>();

          //参数名
         String[] paramNames = ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
         //参数值
         Object[] paramValues = proceedingJoinPoint.getArgs();

         for (int i = 0; i < paramNames.length; i++) {
             Object value = paramValues[i];

             //如果是文件对象
             if (value instanceof MultipartFile) {
                 MultipartFile file = (MultipartFile) value;
                 value = file.getOriginalFilename();  //获取文件名
             }

             requestParams.put(paramNames[i], value);
         }

         return requestParams;
     }

    @After方法调用后执行

    ======>@After("requestServer()")
    public void doAfter(JoinPoint joinPoint) {
        LOGGER.info("===============================End========================");
    }

    <==================>

    最后放一下完整日志请求切面代码:

    @Component
    @Aspect
    public class RequestLogAspect {
        private final static Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);

        @Pointcut("execution(* your_package.controller..*(..))")
        public void requestServer() {
        }

        @Around("requestServer()")
        public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            long start = System.currentTimeMillis();
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            Object result = proceedingJoinPoint.proceed();
            RequestInfo requestInfo = new RequestInfo();
                    requestInfo.setIp(request.getRemoteAddr());
            requestInfo.setUrl(request.getRequestURL().toString());
            requestInfo.setHttpMethod(request.getMethod());
            requestInfo.setClassMethod(String.format("%s.%s", proceedingJoinPoint.getSignature().getDeclaringTypeName(),
                    proceedingJoinPoint.getSignature().getName()));
            requestInfo.setRequestParams(getRequestParamsByProceedingJoinPoint(proceedingJoinPoint));
            requestInfo.setResult(result);
            requestInfo.setTimeCost(System.currentTimeMillis() - start);
            LOGGER.info("Request Info      : {}", JSON.toJSONString(requestInfo));

            return result;
        }


        @AfterThrowing(pointcut = "requestServer()", throwing = "e")
        public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            RequestErrorInfo requestErrorInfo = new RequestErrorInfo();
            requestErrorInfo.setIp(request.getRemoteAddr());
            requestErrorInfo.setUrl(request.getRequestURL().toString());
            requestErrorInfo.setHttpMethod(request.getMethod());
            requestErrorInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
                    joinPoint.getSignature().getName()));
            requestErrorInfo.setRequestParams(getRequestParamsByJoinPoint(joinPoint));
            requestErrorInfo.setException(e);
            LOGGER.info("Error Request Info      : {}", JSON.toJSONString(requestErrorInfo));
        }

        /**
         * 获取入参
         * @param proceedingJoinPoint
         *
         * @return
         * */
        private Map<String, Object> getRequestParamsByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint) {
            //参数名
            String[] paramNames = ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
            //参数值
            Object[] paramValues = proceedingJoinPoint.getArgs();

            return buildRequestParam(paramNames, paramValues);
        }

        private Map<String, Object> getRequestParamsByJoinPoint(JoinPoint joinPoint) {
            //参数名
            String[] paramNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
            //参数值
            Object[] paramValues = joinPoint.getArgs();

            return buildRequestParam(paramNames, paramValues);
        }

        private Map<String, Object> buildRequestParam(String[] paramNames, Object[] paramValues) {
            Map<String, Object> requestParams = new HashMap<>();
            for (int i = 0; i < paramNames.length; i++) {
                Object value = paramValues[i];

                //如果是文件对象
                if (value instanceof MultipartFile) {
                    MultipartFile file = (MultipartFile) value;
                    value = file.getOriginalFilename();  //获取文件名
                }

                requestParams.put(paramNames[i], value);
            }

            return requestParams;
        }

        @Data
        public class RequestInfo {
            private String ip;
            private String url;
            private String httpMethod;
            private String classMethod;
            private Object requestParams;
            private Object result;
            private Long timeCost;
        }

        @Data
        public class RequestErrorInfo {
            private String ip;
            private String url;
            private String httpMethod;
            private String classMethod;
            private Object requestParams;
            private RuntimeException exception;
        }
    }

  • 相关阅读:
    深入理解 Spring 事务原理
    spring+springMVC,声明式事务失效,原因以及解决办法
    spring 中常用的两种事务配置方式以及事务的传播性、隔离级别
    【Spring aop】Spring aop的XML和注解的两种配置实现
    Java消息队列--ActiveMq 实战
    【Android】Android开发实现进度条效果,SeekBar的简单使用。音量,音乐播放进度,视频播放进度等
    【Android】Android开发实现带有反弹效果,仿IOS反弹scrollview详解教程
    【Android】安卓开发之activity如何传值到fragment,activity与fragment传值
    【Android】Android开发初学者实现拨打电话的功能,拨打电话app小demo实现
    【Android】SlidingTabLayout实现标题栏,教你制作title标题 简单易学。
  • 原文地址:https://www.cnblogs.com/KL2016/p/14891722.html
Copyright © 2020-2023  润新知