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 通知允许在方法执行前后和异常情况下插入日志逻辑,适用于统一的日志记录场景。
相关推荐
灰太狼不爱写代码12 分钟前
CUDA11.4版本的Pytorch下载
人工智能·pytorch·笔记·python·学习
数据小爬虫@1 小时前
Java爬虫实战:深度解析Lazada商品详情
java·开发语言
咕德猫宁丶1 小时前
探秘Xss:原理、类型与防范全解析
java·网络·xss
songroom1 小时前
Rust: offset祼指针操作
开发语言·算法·rust
code04号1 小时前
C++练习:图论的两种遍历方式
开发语言·c++·图论
煤泥做不到的!3 小时前
挑战一个月基本掌握C++(第十一天)进阶文件,异常处理,动态内存
开发语言·c++
F-2H3 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
苹果酱05673 小时前
「Mysql优化大师一」mysql服务性能剖析工具
java·vue.js·spring boot·mysql·课程设计
_oP_i4 小时前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx4 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库