Spring AOP 中记录日志

Spring AOP 中记录日志

使用 AOP 和 Spring 提供的 RequestContextHolder 在通知中记录 HTTP 请求相关日志。以下是进阶添加日志功能的完整例子和说明。


完整示例

1. 切面类实现

java 复制代码
@Aspect
@Component
public class LogAspect {

    @Around("@annotation(log)") // 拦截所有标注 @Log 的方法
    public Object logExecution(ProceedingJoinPoint joinPoint, Log log) throws Throwable {
        // 获取 HttpServletRequest 对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 提取请求信息
        String url = request.getRequestURL().toString();
        String method = request.getMethod();
        String ip = request.getRemoteAddr();
        String params = request.getQueryString();

        // 方法名和参数
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();

        // 记录日志 - 方法执行前
        System.out.println("请求 URL: " + url);
        System.out.println("HTTP 方法: " + method);
        System.out.println("请求 IP: " + ip);
        System.out.println("请求参数: " + params);
        System.out.println("方法名称: " + methodName);
        System.out.println("方法参数: " + Arrays.toString(args));

        long startTime = System.currentTimeMillis();

        // 执行目标方法
        Object result;
        try {
            result = joinPoint.proceed(); // 执行被拦截的方法
        } catch (Throwable ex) {
            // 异常处理
            System.err.println("方法执行异常: " + methodName + ", 异常信息: " + ex.getMessage());
            throw ex;
        }

        long timeTaken = System.currentTimeMillis() - startTime;

        // 记录日志 - 方法执行后
        System.out.println("方法执行完成: " + methodName + ", 返回值: " + result + ", 耗时: " + timeTaken + "ms");

        return result; // 返回目标方法的执行结果
    }
}

2. 自定义注解

在需要记录日志的方法上标注自定义注解 @Log:

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

3. 控制器示例

在控制器方法上使用 @Log 注解:

java 复制代码
@RestController
@RequestMapping("/api")
public class TestController {

    @GetMapping("/test")
    @Log("测试日志记录")
    public String testLog(@RequestParam String input) {
        if ("error".equals(input)) {
            throw new RuntimeException("模拟异常");
        }
        return "Hello, " + input;
    }
}

日志输出示例

正常请求

访问 http://localhost:8080/api/test?input=world ,记录如下:

复制代码
请求 URL: http://localhost:8080/api/test
HTTP 方法: GET
请求 IP: 127.0.0.1
请求参数: input=world
方法名称: testLog
方法参数: [world]
方法执行完成: testLog, 返回值: Hello, world, 耗时: 10ms

异常请求

访问 http://localhost:8080/api/test?input=error ,记录如下:

复制代码
请求 URL: http://localhost:8080/api/test
HTTP 方法: GET
请求 IP: 127.0.0.1
请求参数: input=error
方法名称: testLog
方法参数: [error]
方法执行异常: testLog, 异常信息: 模拟异常

关键点解析

1. 为什么使用 RequestContextHolder?

  • HttpServletRequest 是与线程绑定的,通过 RequestContextHolder 可以方便地在 AOP 切面中获取当前请求的 HttpServletRequest 对象。

2. 日志内容可记录什么?

  • 请求的 URL (request.getRequestURL());
  • HTTP 方法 (request.getMethod());
  • 客户端 IP 地址 (request.getRemoteAddr());
  • 请求参数 (request.getQueryString());
  • 被拦截方法的名称和参数 (joinPoint.getSignature()joinPoint.getArgs());
  • 方法执行耗时。

3. 异常处理

  • catch 块中记录方法执行时报出的异常信息,以便后续排查问题。

总结

  • 通过 AOP 和 RequestContextHolder ,在通知中进行统一的日志记录,便于跟踪和排查 HTTP 请求相关的信息。
  • @Around 通知允许在方法执行前后和异常情况下插入日志逻辑,适用于统一的日志记录场景。
相关推荐
AI情绪识别开源13 分钟前
检信AI高一分班分科智选评估系统 v2.0测试报告
开发语言·数据结构·人工智能·科技
纯.Pure_Jin(g)18 分钟前
靶场PHP函数整理+防御方式
开发语言·php·ctf
IT毕设实战小研24 分钟前
电影数据可视化推荐系统
大数据·后端·爬虫·python·算法·信息可视化·课程设计
ssshooter29 分钟前
AI 时代你不能不知道的 git worktree
前端·后端·面试
weixin_466068111 小时前
《十分钟冥想》精读笔记(上):每天10分钟,给大脑做一次“系统减负”
笔记
CoderYanger1 小时前
A.每日一题:输入单词需要的最少按键次数 Ⅰ+Ⅱ
java·数据结构·算法·leetcode·面试
Cosolar1 小时前
一文弄懂 Agent Harness 与 Agent Runtime 的区别
java·后端·github
海兰1 小时前
【 Python 量化交易】第3章:金融基础概念
开发语言·python·金融
一木 之林1 小时前
三.C++ 内存管理(进阶)(二)
开发语言·arm开发·c++
吴声子夜歌1 小时前
Java——类、对象及方法(一)
java·开发语言