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.结果
相关推荐
陌殇殇21 分钟前
002 SpringCloudAlibaba整合 - Feign远程调用、Loadbalancer负载均衡
java·spring cloud·微服务
猎人everest1 小时前
SpringBoot应用开发入门
java·spring boot·后端
山猪打不过家猪3 小时前
ASP.NET Core Clean Architecture
java·数据库·asp.net
AllowM3 小时前
【LeetCode Hot100】除自身以外数组的乘积|左右乘积列表,Java实现!图解+代码,小白也能秒懂!
java·算法·leetcode
不会Hello World的小苗4 小时前
Java——列表(List)
java·python·list
二十七剑5 小时前
jvm中各个参数的理解
java·jvm
东阳马生架构6 小时前
JUC并发—9.并发安全集合四
java·juc并发·并发安全的集合
计算机小白一个7 小时前
蓝桥杯 Java B 组之岛屿数量、二叉树路径和(区分DFS与回溯)
java·数据结构·算法·蓝桥杯
菠菠萝宝7 小时前
【Java八股文】10-数据结构与算法面试篇
java·开发语言·面试·红黑树·跳表·排序·lru
不会Hello World的小苗7 小时前
Java——链表(LinkedList)
java·开发语言·链表