zoukankan      html  css  js  c++  java
  • AOP-配合slf4j打印日志

    基本思想

    1. 凡在目标实例上或在目标实例方法(非静态方法)上标注自定义注解@AutoLog,其方法执行时将触发AOP操作;
    2. @AutoLog只有一个参数,用来控制是否打印该方法的参数和返回结果的json字符串,默认不打印,通过@AutoLog(true)开启
    3. 通过AOP拦截方法并打印日志

    代码

    package com.yan.mssm.aop;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AutoLog {
        // log params and result when true
        boolean value() default false;
    }
    
    package com.yan.mssm.aop;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.aop.framework.AdvisedSupport;
    import org.springframework.aop.framework.AopProxy;
    import org.springframework.aop.support.AopUtils;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.el.MethodNotFoundException;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.*;
    import java.util.stream.Collectors;
    
    @Component
    @Aspect
    public class AutoLogAspectJ {
        private static final String PREFIX = "[";
        private static final String SUFFIX = "]";
        private static final String END = "end";
        private static final String BEGIN = "begin";
        private static final String PARAMS = "params";
        private static final String RESULT = "result";
        private static final String DELIMITER = " || ";
        private static final int STRING_MAX_LENGTH = 1 << 10;
        private static final Class<AutoLog> AUTO_LOG_CLASS = AutoLog.class;
        private static final String LOG_FORMAT = "[AOP-LOG]->Method {}: {}";
        private static final Class<RequestMapping> REQUEST_MAPPING_CLASS = RequestMapping.class;
        private static Logger LOGGER;
        private Method method;
        private String url;
        private Class<?> targetClass;
        private String methodSignature;
        private boolean debug;
    
        private static Object getCglibProxyTargetObject(Object proxy) {
            Field h;
            try {
                h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
                h.setAccessible(true);
                Object dynamicAdvisedInterceptor = h.get(proxy);
                Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
                advised.setAccessible(true);
                return ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
            } catch (Exception e) {
                return null;
            }
        }
    
        private static Object getJdkDynamicProxyTargetObject(Object proxy) {
            try {
                Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
                h.setAccessible(true);
                AopProxy aopProxy = (AopProxy) h.get(proxy);
                Field advised = aopProxy.getClass().getDeclaredField("advised");
                advised.setAccessible(true);
                return ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
            } catch (Exception e) {
                return null;
            }
        }
    
        private Object getTarget(Object proxy) {
            if (!AopUtils.isAopProxy(proxy)) {
                return proxy;
            }
            if (AopUtils.isJdkDynamicProxy(proxy)) {
                return getJdkDynamicProxyTargetObject(proxy);
            }
            return getCglibProxyTargetObject(proxy);
        }
    
        @Around(value = "@within(com.yan.mssm.aop.AutoLog) || @annotation(com.yan.mssm.aop.AutoLog)")
        public Object test(ProceedingJoinPoint point) throws Throwable {
            init(point);
            Optional.ofNullable(url).ifPresent(u -> LOGGER.info("[AOP-LOG]->Input URL:{}", u));
            LOGGER.info(LOG_FORMAT, BEGIN, methodSignature);
            printParams(point);
            Object result = point.proceed();
            printResult(result);
            LOGGER.info(LOG_FORMAT, END, methodSignature);
            return result;
        }
    
        private void init(ProceedingJoinPoint point) {
            Signature signature = point.getSignature();
            methodSignature = signature.toString();
            targetClass = point.getTarget().getClass();
            LOGGER = LoggerFactory.getLogger(targetClass);
            method = Arrays.stream(targetClass.getDeclaredMethods())
                    .filter(method -> method.toString().equals(signature.toLongString()))
                    .findFirst().orElseThrow(MethodNotFoundException::new);
            setUrl();
            debug = isDebug();
        }
    
        private void printResult(Object result) {
            if (!debug) {
                return;
            }
            Optional.ofNullable(result).ifPresent(r -> LOGGER.info(LOG_FORMAT, RESULT, r));
        }
    
        private void printParams(ProceedingJoinPoint point) {
            if (!debug) {
                return;
            }
            Object[] args = point.getArgs();
            if (args.length == 0) {
                return;
            }
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            String[] paramNames = methodSignature.getParameterNames();
            Map<String, Object> argMap = new LinkedHashMap<>();
            for (int i = 0; i < args.length; i++) {
                String argName = paramNames[i];
                argMap.put(argName, getTarget(args[i]));
            }
            String paramString = toJsonString(argMap);
            Optional.ofNullable(paramString)
                    .ifPresent(str -> LOGGER.info(LOG_FORMAT, PARAMS, str));
        }
    
        private boolean isDebug() {
            return (targetClass.isAnnotationPresent(AUTO_LOG_CLASS) && targetClass.getAnnotation(AUTO_LOG_CLASS).value())
                    || (method.isAnnotationPresent(AutoLog.class) && method.getAnnotation(AUTO_LOG_CLASS).value());
        }
    
        private void setUrl() {
            boolean controller = targetClass.isAnnotationPresent(RestController.class)
                    || targetClass.isAnnotationPresent(Controller.class);
    
            if (!controller) {
                url = null;
                return;
            }
    
            List<String> urlList = getUrlList();
            url = getCollect(urlList);
        }
    
        private List<String> getUrlList() {
            List<String> urlList = new ArrayList<>();
            String[] urls;
    
            boolean hasControllerMapping = hasControllerMapping();
            boolean hasMethodMapping = hasMethodMapping();
            if (!hasControllerMapping && !hasMethodMapping) {
                return urlList;
            }
    
            if (!hasControllerMapping) {
                urls = method.getAnnotation(REQUEST_MAPPING_CLASS).value();
                urlList.addAll(Arrays.asList(urls));
                return urlList;
            }
    
            if (!hasMethodMapping) {
                urls = targetClass.getAnnotation(REQUEST_MAPPING_CLASS).value();
                urlList.addAll(Arrays.asList(urls));
                return urlList;
            }
    
            Arrays.stream(targetClass.getAnnotation(REQUEST_MAPPING_CLASS).value())
                    .forEach(ctlrUrl ->
                            Arrays.stream(method.getAnnotation(REQUEST_MAPPING_CLASS).value())
                                    .forEach(methodUrl -> {
                                        StringBuilder sbd = new StringBuilder();
                                        urlList.add(sbd.append(ctlrUrl).append(methodUrl).toString());
                                    }));
            return urlList;
        }
    
        private boolean hasMethodMapping() {
            return method.isAnnotationPresent(REQUEST_MAPPING_CLASS)
                    && method.getAnnotation(REQUEST_MAPPING_CLASS).value().length > 0;
        }
    
        private boolean hasControllerMapping() {
            return targetClass.isAnnotationPresent(REQUEST_MAPPING_CLASS)
                    && targetClass.getAnnotation(REQUEST_MAPPING_CLASS).value().length > 0;
        }
    
        private String getCollect(List<String> urlList) {
            return urlList.stream().collect(Collectors.joining(DELIMITER, PREFIX, SUFFIX));
        }
    
        private String toJsonString(Object object) {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
            String result = null;
            try {
                byte[] bytes = objectMapper.writeValueAsBytes(object);
                result = new String(bytes, "utf-8");
                result = result.length() > STRING_MAX_LENGTH ? null : result;
            } catch (Exception e) {
                LOGGER.error("AutoLogAspectJ.toJsonString exception:
    {}", e.getMessage());
            }
            return result;
        }
    }
    
  • 相关阅读:
    RE
    【LeetCode】198. House Robber
    【LeetCode】053. Maximum Subarray
    【LeetCode】152. Maximum Product Subarray
    【LeetCode】238.Product of Array Except Self
    【LeetCode】042 Trapping Rain Water
    【LeetCode】011 Container With Most Water
    【LeetCode】004. Median of Two Sorted Arrays
    【LeetCode】454 4Sum II
    【LeetCode】259 3Sum Smaller
  • 原文地址:https://www.cnblogs.com/yw0219/p/8627988.html
Copyright © 2011-2022 走看看