AOP实现操作日志记录

文章目录

    • 1.common-log4j2-starter
        • 1.目录
        • [2.pom.xml 引入依赖](#2.pom.xml 引入依赖)
        • 3.LogAspect.java
        • [4.Log4j2AutoConfiguration.java Log4j2自动配置类条件注入切面类](#4.Log4j2AutoConfiguration.java Log4j2自动配置类条件注入切面类)
    • [2.common-log4j2-starter-demo 测试](#2.common-log4j2-starter-demo 测试)

1.common-log4j2-starter

1.目录
2.pom.xml 引入依赖
xml 复制代码
<!-- aop -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- gson -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>
3.LogAspect.java
java 复制代码
package com.sunxiansheng.log4j2.aspectj;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect
@Slf4j
public class LogAspect {

    // 使用 Gson 序列化对象,启用 PrettyPrinting,输出格式化的 JSON
    private static final Gson GSON = new GsonBuilder()
            .setPrettyPrinting() // 启用格式化输出
            .disableHtmlEscaping() // 禁用 HTML 转义,保留字符原始形式
            .create();

    // ANSI 颜色代码
    private static final String ANSI_RESET = "\u001B[0m";     // 重置颜色
    private static final String ANSI_CYAN = "\u001B[92m";     // 绿色

    /**
     * 配置切点,匹配 Controller 和 Service 层的所有方法
     */
    @Pointcut("execution(* com.sunxiansheng..controller..*(..)) || execution(* com.sunxiansheng..service..*(..))")
    public void applicationPackagePointcut() {
        // 方法为空,这是一个切点定义
    }

    /**
     * 环绕通知,记录方法执行的详细信息
     *
     * @param joinPoint 切入点
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Around("applicationPackagePointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名和详细信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String className = signature.getDeclaringTypeName();
        String methodName = signature.getName();

        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        String requestParams = GSON.toJson(args);

        // 记录方法进入日志,参数从下一行开始输出,参数部分以黄色显示
        log.info("==> 进入方法: {}.{}()", className, methodName);
        log.info("参数:\n" + ANSI_CYAN + "{}" + ANSI_RESET, requestParams);

        // 记录方法执行开始时间
        long startTime = System.currentTimeMillis();

        Object result;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            // 捕获并记录异常信息,堆栈信息从下一行开始输出
            String exceptionStackTrace = getStackTraceAsString(throwable);
            log.error("<== 方法异常: {}.{}() | 异常信息: {}", className, methodName, throwable.getMessage());
            log.error("堆栈信息:\n{}", exceptionStackTrace);
            throw throwable;  // 重新抛出异常,保持原有异常机制
        }

        // 记录方法执行结束时间
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;

        // 获取方法返回值
        String response = GSON.toJson(result);

        // 记录方法退出日志,返回值从下一行开始输出,返回值部分以黄色显示
        log.info("<== 退出方法: {}.{}() | 耗时: {} ms", className, methodName, executionTime);
        log.info("返回值:\n" + ANSI_CYAN + "{}" + ANSI_RESET, response);

        return result;
    }

    /**
     * 将异常的堆栈信息转换为字符串
     *
     * @param throwable 异常
     * @return 堆栈信息字符串
     */
    private String getStackTraceAsString(Throwable throwable) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : throwable.getStackTrace()) {
            sb.append("\tat ").append(element.toString()).append("\n");
        }
        return sb.toString();
    }
}
4.Log4j2AutoConfiguration.java Log4j2自动配置类条件注入切面类
java 复制代码
package com.sunxiansheng.log4j2.config;

import com.sunxiansheng.log4j2.aspectj.LogAspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description: Log4j2自动配置类
 *
 * @Author sun
 * @Create 2024/10/24 10:36
 * @Version 1.0
 */
@Configuration
public class Log4j2AutoConfiguration {

    /**
     * 条件注入LogAspect
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "log.aspect.enable", havingValue = "true", matchIfMissing = true)
    LogAspect logAspect() {
        return new LogAspect();
    }
}

2.common-log4j2-starter-demo 测试

1.目录
2.application.yml 启用日志切面
yaml 复制代码
log:
  aspect:
    enable: true # 开启自定义的日志切面
3.TraceController.java
java 复制代码
/**
 * 测试的Bean,入参
 */
@Data
static class AspectBeanIn {
    private String name;
    private Integer age;
    private String phone;
}

/**
 * 测试的Bean,出参
 */
@Data
static class AspectBeanOut {
    private String name;
    private Integer age;
    private String phone;
}

@RequestMapping("/aspect")
public AspectBeanOut aspect(@RequestBody AspectBeanIn aspectBeanIn) {
    AspectBeanOut aspectBean = new AspectBeanOut();
    aspectBean.setName("sun");
    aspectBean.setAge(18);
    aspectBean.setPhone("123456789");
    // 出现异常
    int i = 1 / 0;
    return aspectBean;
}
4.结果
相关推荐
程序员欣宸10 小时前
LangChain4j实战之十三:函数调用,低级API版本
java·人工智能·ai·langchain4j
Java新手村10 小时前
【订单超时取消怎么设计】
java
阿蒙Amon11 小时前
C#每日面试题-常量和只读变量的区别
java·面试·c#
寻星探路11 小时前
【算法专题】滑动窗口:从“无重复字符”到“字母异位词”的深度剖析
java·开发语言·c++·人工智能·python·算法·ai
程序员小白条11 小时前
面试 Java 基础八股文十问十答第八期
java·开发语言·数据库·spring·面试·职场和发展·毕设
萤丰信息11 小时前
从 “钢筋水泥” 到 “数字神经元”:北京 AI 原点社区重构城市进化新逻辑
java·大数据·人工智能·安全·重构·智慧城市·智慧园区
week_泽12 小时前
第5课:短期记忆与长期记忆原理 - 学习笔记_5
java·笔记·学习·ai agent
像风一样自由12 小时前
android native 中的函数动态注册方式总结
android·java·服务器·安卓逆向分析·native函数动态注册·.so文件分析
兮动人13 小时前
Maven指定加载的类
java·maven·maven指定加载的类
wangkay8813 小时前
【Java 转运营】Day04:抖音新号起号前准备全指南
java·开发语言·新媒体运营