Spring Aop实现日志切面

Spring Aop实现日志切面

LogAspect

@Aspect
@Component
@Slf4j
public class LogAspect {

    /**
     * 请求Id
     */
    private static final String REQ_ID = "requestId";

    /**
     * 注解切面
     */
    @Pointcut("@annotation(com.demo.annotation.InsLog)")
    public void pointcutInterface() {
    }

    /**
     * 需要排除的包切面
     */
    @Pointcut("!execution(* com.demo.exclued*.*(..))")
    public void excludePackage() {
    }

    /**
     * 需要处理的包切面
     */
    @Pointcut("execution(* com.demo.rpc..*.*(..)) || execution(* com.demo.service..*.*(..)))")
    public void pointcutPackage() {
    }

    @Around("(pointcutInterface() || pointcutPackage()) && excludePackage()")
    public Object doAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        Map<String, String> mdc = MDC.getCopyOfContextMap();
        String key = joinPoint.getTarget().getClass().getSimpleName() + "#" + getMethodName(joinPoint) + "()";
        Object[] args = joinPoint.getArgs();
        // 日志说明
        String logDesc = "";
        // 是否需要输出指定环节日志
        boolean reqLog = true,resLog = false, cost = true, throwEx = false;
        // 获取日志注解
        InsLog insLog = getInsLog(joinPoint);
        if (null != insLog) {
            logDesc = insLog.desc();
            reqLog = insLog.reqLog();
            resLog = insLog.resLog();
            cost = insLog.cost();
            throwEx = insLog.throwEx();
        }
        // 用于区分一次线程请求
        String reqId = MDC.get(REQ_ID);
        if (StringUtils.isBlank(reqId)) {
            reqId = System.currentTimeMillis() + "-" + Arrays.hashCode(args);
            MDC.put(REQ_ID, reqId);
        }
        Object res;
        if (reqLog) {
            log.info("【Log {}请求】{},参数={}", logDesc, key, JSONObject.toJSONString(args));
        }
        long beginMs = System.currentTimeMillis();
        try {
            res = joinPoint.proceed();
            // 由于多线程,会导致MDC清空,此处补全
            if (StringUtils.isBlank(MDC.get(REQ_ID))) {
                MDC.setContextMap(mdc);
            }
            if (resLog) {
                long costTime = 0L;
                if (cost) {
                    costTime = System.currentTimeMillis() - beginMs;
                }
                log.info("【Log {}返回】{}{},结果={}", logDesc, key, costTime > 0L ? " 耗时=" + costTime + "ms" : "", JSONObject.toJSONString(res));
            }
            return res;
        } catch (Exception e) {
            if (!reqLog) {
                // 异常情况同时打印请求日志
                log.error("【Log {}异常】{},参数={}", logDesc, key, JSONObject.toJSONString(args));
            }
            if (throwEx) {
                // 是否打印异常堆栈
                log.error("【Log {}异常】{},处理异常", logDesc, key, e);
            } else {
                log.error("【Log {}请求】{},处理异常", logDesc, key);
            }
            throw e;
        }
    }

    /**
     * 获取InsLog
     *
     * @param joinPoint ProceedingJoinPoint
     * @return InsLog
     */
    private InsLog getInsLog(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            return methodSignature.getMethod().getAnnotation(InsLog.class);
        }
        return null;
    }

    /**
     * 获取方法名
     *
     * @param joinPoint ProceedingJoinPoint
     * @return 方法名
     */
    private String getMethodName(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            return methodSignature.getMethod().getName();
        }
        return "未获取到方法";
    }
}

InsLog

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface InsLog {
    /**
     * 中文方法名
     */
    String desc() default "";

    /**
     * 是否打印入参日志,默认是
     */
    boolean reqLog() default true;

    /**
     * 是否打印出参日志,默认是
     */
    boolean resLog() default false;

    /**
     * 是否打印耗时日志,默认是
     */
    boolean cost() default true;

    /**
     * 是否打印堆栈,默认打印
     *
     * @return 打印堆栈
     */
    boolean throwEx() default true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值