MethodInterceptor的使用与AOP的关系解读
作者:一恍过去
本文比较了AOP切面和MethodInterceptor对代码增强处理的不同方式,指出MethodInterceptor更加轻便且可以自定义排序,通过实际代码验证了AOP和Interceptor的结合使用情况,并分析了两者在实现方式、定位、抽象层级、性能开销等方面的差异
前言
项目中可以使用AOP切面来进行增强处理,也可以自行实现一个MethodInterceptor对代码进行增强处理,相比与使用AOP可以更加轻便的形成连接器链;
使用
引入POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
配置Interceptor
import jakarta.annotation.Resource;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ServiceInterceptorConfig {
private static final String EXECUTION = "execution(* com.lhz.demo.service.UserService.*(..))";
@Resource
private ServiceInterceptor serviceInterceptor;
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(EXECUTION);
advisor.setPointcut(pointcut);
advisor.setAdvice(serviceInterceptor);
advisor.setOrder(-1);
return advisor;
}
}
自定义Interceptor
@Component
@Slf4j
public class ServiceInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
log.info("进入ServiceInterceptor...");
Object[] arguments = methodInvocation.getArguments();
return methodInvocation.proceed();
}
}
排序
单个Interceptor、多个Interceptor、AOP使用的相同的pointcut时,请求都会进入,只是进入的先后顺序不同,AOP中可以直接通过@Order注解控制,Interceptor通过advisor.setOrder()方法进行设置;
验证
同时存在AOP和Interceptor的情况,并且AOP的order=-2,Interceptor的order=-1
AOP代码如下:
@Aspect
@Component
@Slf4j
@Order(-2)
public class ServiceAop {
@Pointcut("execution(* com.lhz.demo.service.UserService.*(..))")
public void point() {
}
@Before("point()")
public void doBeforeAdvice(JoinPoint point) {
log.info("进入前置通知...");
}
@Around("point()")
public void doAroundAdvice(ProceedingJoinPoint point) throws Throwable {
log.info("进入环绕通知...");
point.proceed();
}
}
结果:

对比
| 对比维度 | MethodInterceptor | AOP (广义) |
|---|---|---|
| 定位 | AOP 的具体实现组件 | 编程范式/思想 |
| 抽象层级 | 具体的技术实现 | 高层次的设计理念 |
| 标准化 | AOP Alliance 标准接口 | 无统一标准,各框架实现不同 |
核心差异
| 特性 | MethodInterceptor | 声明式AOP | 差异分析 |
|---|---|---|---|
| 实现方式 | 实现MethodInterceptor接口 | 使用@Aspect注解 | 前者需手动编码,后者通过元数据配置 |
| 拦截粒度 | 方法调用级别控制 | 切入点表达式匹配 | MethodInterceptor可获取MethodInvocation完整上下文 |
| 执行控制 | 显式调用invocation.proceed() | 隐式调用joinPoint.proceed() | 前者对执行流程控制更直观 |
| 性能开销 | △ 较低(直接方法调用) | ○ 略高(需解析注解) | 差异在微秒级,高并发场景需考虑 |
| 适用阶段 | 动态代理 | 支持LTW/CTW | AspectJ的编译时织入能力更强 |
| 依赖关系 | 仅依赖AOP Alliance API | 依赖具体框架(如Spring AOP) | 前者更易移植 |
| 调试复杂度 | 需跟踪代理链 | 切面集中管理 | 声明式AOP的堆栈信息更友好 |
| 动态能力 | ★★★★ 可运行时修改拦截逻辑 | ★★ 配置后固定 | MethodInterceptor适合需要热更新的场景 |
| 代码侵入性 | 目标类无需修改 | 但需引入AOP依赖 | 两者都符合AOP的非侵入理念 |
| 典型应用场景 | 安全校验/参数过滤/熔断机制 | 日志/事务/缓存等常规切面 | 根据业务复杂度选择 |
注:实际使用时建议将图标替换为对应的emoji或移除图标标记
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
