Spring方法拦截器MethodInterceptor和AOP统一处理log

本文介绍了一种利用AOP(面向切面编程)技术来记录HTTP接口请求日志的方法。通过自定义`ControllerMethodInterceptor`拦截器,可以在Spring MVC应用中自动记录请求参数及返回值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对每个接口的请求记录log的方法有很多种,比如用filter、mvc interceptor、method interceptor等。如果需要记录请求消息的payload,前两种不适用。下面介绍第三种的实现方法。


第一步:引入包依赖

[java]  view plain  copy
  1. <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="java">      <!-- For AOP -->        
  2.         <dependency>  
  3.             <groupId>org.aspectj</groupId>  
  4.             <artifactId>aspectjweaver</artifactId>  
  5.             <version>1.8.6</version>  
  6.         </dependency>  
  7.         <!-- databind会自动引用core和annotations,所以不用声明另外两个 -->  
  8.         <dependency>  
  9.             <groupId>com.fasterxml.jackson.core</groupId>  
  10.             <artifactId>jackson-databind</artifactId>  
  11.             <version>2.5.3</version>  
  12.         </dependency>  


 
[java]  view plain  copy
  1. <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">(其他log、spring包依赖:略)</span>  

第二步:继承org.aopalliance.intercept.MethodInterceptor,实现invoke方法:

[java]  view plain  copy
  1. /** 
  2.  * 方法拦截器,拦截Controller中的方法,记录log 
  3.  * 
  4.  */  
  5. public class ControllerMethodInterceptor implements MethodInterceptor {  
  6.     private final Logger logger = LoggerFactory.getLogger(this.getClass());  
  7.       
  8.     private final static ObjectMapper jsonMapper = new ObjectMapper();  
  9.   
  10.     @Override  
  11.     public Object invoke(MethodInvocation invocation) throws Throwable {  
  12.         logger.info("Before: interceptor name: {}", invocation.getMethod().getName());  
  13.           
  14.         logger.info("Arguments: {}", jsonMapper.writeValueAsString(invocation.getArguments()));  
  15.           
  16.         Object result = invocation.proceed();  
  17.           
  18.         logger.info("After: result: {}", jsonMapper.writeValueAsString(result));  
  19.           
  20.         return result;  
  21.     }  
  22.   
  23. }  

第三步:配置拦截

[java]  view plain  copy
  1. <bean id="controllerMethodInterceptor" class="com.xjj.web.interceptor.ControllerMethodInterceptor"/>  
  2.   
  3. <!-- 方法拦截器(拦截Controller包中的所有被RequestMapping注解的方法) MethodInterceptor -->  
  4. <aop:config proxy-target-class="true">  
  5.     <aop:pointcut id="controllerMethodPointcut" expression="execution(* com.xjj.web.controller..*(..)) and  
  6.         @annotation(org.springframework.web.bind.annotation.RequestMapping)"/>  
  7.     <aop:advisor advice-ref="controllerMethodInterceptor" pointcut-ref="controllerMethodPointcut" />  
  8. </aop:config>  

这样,所有com.xjj.web.controller包中的被RequestMapping注解的方法都会被ControllerMethodInterceptor拦截。在ControllerMethodInterceptor中,可以记录被拦截的方法中的参数、返回值等。


具体的全部代码请参考:https://github.com/xujijun/MyJavaStudio


(原创文章,转载请注明转自Clement-Xu的博客)

### AOP 拦截器的使用及实现原理 #### 一、AOP拦截器的概念 在面向切面编程(AOP, Aspect-Oriented Programming)中,拦截器是一种机制,用于在特定方法执行前后插入自定义逻辑。Spring框架中的AOP拦截器主要由`Advisor``MethodInterceptor`组成[^3]。 - **Advisor**: 定义了切点(Pointcut)通知(Advice)。切点决定了哪些方法会被拦截,而通知则描述了拦截时的具体行为。 - **MethodInterceptor**: 是一种具体的 Advice 类型,它允许开发者在目标方法执行前或后加入额外的操作。 --- #### 二、AOP拦截器的工作流程 当一个方法被调用时,如果该方法匹配某个切点条件,则会触发拦截器链的执行。以下是具体工作流程: 1. 判断是否存在拦截器链。如果没有拦截器链,则直接执行目标对象的方法[^2]。 2. 如果存在拦截器链,则将这些拦截器封装为 `ReflectiveMethodInvocation` 对象,并通过其 `proceed()` 方法依次调用各个拦截器。 3. 在拦截器链中,每个拦截器可以决定是否继续向下传递请求或者中断整个调用链条。 4. 当所有拦截器都完成操作后,最终返回目标方法的执行结果。 --- #### 三、AOP拦截器的实现细节 ##### 1. JDK 动态代理与 CGLIB 的区别 Spring AOP 支持两种代理模式:JDK动态代理CGLIB代理。两者的实现方式略有不同,但核心思想一致。 - **JDK动态代理**: - 需要目标类实现接口。 - 使用 `JdkDynamicAopProxy` 的 `invoke` 方法来拦截目标方法的调用。 ```java public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ReflectiveMethodInvocation invocation = new JdkDynamicMethodInvocation(targetObject, targetClass, method, args); return invocation.proceed(); } ``` - **CGLIB代理**: - 不依赖于接口,适用于未实现任何接口的目标类。 - 使用 `DynamicAdvisedInterceptor` 的 `intercept` 方法来进行拦截。 ```java @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { ReflectiveMethodInvocation invocation = new CglibMethodInvocation(advised, targetSource.getTarget(), method, args); return invocation.proceed(); } ``` ##### 2. 拦截器链的核心组件——`ReflectiveMethodInvocation` `ReflectiveMethodInvocation` 是 Spring AOP 实现的关键类之一,负责管理拦截器链并控制方法调用的过程。它的 `proceed()` 方法实现了递归调用拦截器的功能。 ```java @Override public Object proceed() throws Throwable { if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) { // 执行实际的目标方法 return invokeJoinpoint(); } // 获取当前拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(this.currentInterceptorIndex++); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 处理动态切点... } else { // 调用下一个拦截器 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } ``` 上述代码展示了如何逐个调用拦截器链中的每一个拦截器,并最终到达目标方法的执行阶段。 --- #### 四、AOP拦截器的实际应用 以下是一个简单的 Kotlin 示例,展示如何配置使用 AOP 拦截器。此示例也可以轻松转换为 Java 版本[^1]。 ```kotlin @Aspect class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") fun logBefore(joinPoint: JoinPoint) { println("Logging before method ${joinPoint.signature.name}") } @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result") fun logAfterReturning(result: Any?) { println("Method returned with result $result") } } @Service class MyService { fun doSomething(): String { return "Hello from service" } } ``` 在这个例子中: - `@Before` 注解表示在指定方法执行之前记录日志。 - `@AfterReturning` 注解表示在方法成功返回之后记录返回值。 --- #### 五、总结 AOP拦截器Spring AOP 的重要组成部分,能够帮助开发者分离关注点,在不修改业务逻辑的情况下增强功能。其实现基于代理模式(JDK 或 CGLIB),并通过拦截器链的方式灵活地处理多个切面需求。理解其底层原理有助于更好地利用这一强大工具优化应用程序设计。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值