从零到一写组件库-日志组件库

组件概述

  1. 方法或类上添加日志打印注解并打印日志

组件POM

pom 复制代码
<dependency>
  <groupId>org.opengoofy.index12306</groupId>
  <artifactId>aska12306-log-spring-boot-starter</artifactId>
  <version>${project.version}</version>
</dependency>

组件功能

1. 日志打印

  • 定义日志打印注解,可以标记在类或者方法上。

  • 标记在类上,类下所有方法都会打印;标记在方法上,仅打印标记方法;如果类或者方法上都有标记,以方法上注解为准

java 复制代码
package com.opengoofy.aska12306.framework.starter.log.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Log 注解打印,可以标记在类或者方法上
 * 标记在类上,类下所有方法都会打印;标记在方法上,仅打印标记方法;如果类或者方法上都有标记,以方法上注解为准
 * aska12306
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ILog {

    /**
     * 入参打印
     *
     * @return 打印结果中是否包含入参,{@link Boolean#TRUE} 打印,{@link Boolean#FALSE} 不打印
     */
    boolean input() default true;

    /**
     * 出参打印
     *
     * @return 打印结果中是否包含出参,{@link Boolean#TRUE} 打印,{@link Boolean#FALSE} 不打印
     */
    boolean output() default true;
}

定义日志打印规约参数,共打印参数:开始时间、请求入参、以及返回参数等

java 复制代码
package com.opengoofy.aska12306.framework.starter.log.core;

import lombok.Data;

/**
 * ILog 日志打印实体
 * aska12306
 */
@Data
public class ILogPrintDTO {

    /**
     * 开始时间
     */
    private String beginTime;

    /**
     * 请求入参
     */
    private Object[] inputParams;

    /**
     * 返回参数
     */
    private Object outputParams;
}
  • 定义日志注解 AOP 扫描类,执行方法执行前后增强,最终打印方法执行日志。

  • @within@annotation 注解分别对注解在类上和在方法上增强

  • 特别是 @within 这个很少用到 而对于 @annotation 相信大家基本上是见怪不怪了

java 复制代码
package com.opengoofy.aska12306.framework.starter.log.core;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.SystemClock;
import com.alibaba.fastjson2.JSON;
import com.opengoofy.aska12306.framework.starter.log.annotation.ILog;
import org.aspectj.lang.ProceedingJoinPoint;
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.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Optional;

/**
 * {@link ILog} 日志打印 AOP 切面
 * aska12306
 */
@Aspect
public class ILogPrintAspect {

    /**
     * 打印类或方法上的 {@link ILog}
     */
    @Around("@within(com.opengoofy.aska12306.framework.starter.log.annotation.ILog) || @annotation(com.opengoofy.aska12306.framework.starter.log.annotation.ILog)")
    public Object printMLog(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = SystemClock.now();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Logger log = LoggerFactory.getLogger(methodSignature.getDeclaringType());
        String beginTime = DateUtil.now();
        Object result = null;
        try {
            result = joinPoint.proceed();
        } finally {
            Method targetMethod = joinPoint.getTarget().getClass().getDeclaredMethod(methodSignature.getName(), methodSignature.getMethod().getParameterTypes());
            ILog logAnnotation = Optional.ofNullable(targetMethod.getAnnotation(ILog.class)).orElse(joinPoint.getTarget().getClass().getAnnotation(ILog.class));
            if (logAnnotation != null) {
                ILogPrintDTO logPrint = new ILogPrintDTO();
                logPrint.setBeginTime(beginTime);
                if (logAnnotation.input()) {
                    logPrint.setInputParams(buildInput(joinPoint));
                }
                if (logAnnotation.output()) {
                    logPrint.setOutputParams(result);
                }
                String methodType = "", requestURI = "";
                try {
                    ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                    assert servletRequestAttributes != null;
                    methodType = servletRequestAttributes.getRequest().getMethod();
                    requestURI = servletRequestAttributes.getRequest().getRequestURI();
                } catch (Exception ignored) {
                }
                log.info("[{}] {}, executeTime: {}ms, info: {}", methodType, requestURI, SystemClock.now() - startTime, JSON.toJSONString(logPrint));
            }
        }
        return result;
    }

    private Object[] buildInput(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Object[] printArgs = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if ((args[i] instanceof HttpServletRequest) || args[i] instanceof HttpServletResponse) {
                continue;
            }
            if (args[i] instanceof byte[]) {
                printArgs[i] = "byte array";
            } else if (args[i] instanceof MultipartFile) {
                printArgs[i] = "file";
            } else {
                printArgs[i] = args[i];
            }
        }
        return printArgs;
    }
}
相关推荐
Victor35611 小时前
https://editor.csdn.net/md/?articleId=139321571&spm=1011.2415.3001.9698
后端
Victor35611 小时前
Hibernate(89)如何在压力测试中使用Hibernate?
后端
灰子学技术13 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
Gogo81614 小时前
BigInt 与 Number 的爱恨情仇,为何大佬都劝你“能用 Number 就别用 BigInt”?
后端
fuquxiaoguang14 小时前
深入浅出:使用MDC构建SpringBoot全链路请求追踪系统
java·spring boot·后端·调用链分析
毕设源码_廖学姐15 小时前
计算机毕业设计springboot招聘系统网站 基于SpringBoot的在线人才对接平台 SpringBoot驱动的智能求职与招聘服务网
spring boot·后端·课程设计
野犬寒鸦16 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
逍遥德17 小时前
如何学编程之01.理论篇.如何通过阅读代码来提高自己的编程能力?
前端·后端·程序人生·重构·软件构建·代码规范
MX_935917 小时前
Spring的bean工厂后处理器和Bean后处理器
java·后端·spring
程序员泠零澪回家种桔子18 小时前
Spring AI框架全方位详解
java·人工智能·后端·spring·ai·架构