Java案例实战:拦截数据哪队更好?Filter、Interceptor与AOP深度对决
目录导读
- 开篇:一个真实Java项目引发的"拦截之争"
- 三队选手登场:Filter、Interceptor、AOP各是什么
- Java案例实战:同一需求三种写法
- 核心维度对比:谁更胜一筹
- 常见问答Q&A
- 没有最好,只有最合适
开篇:一个真实Java项目引发的"拦截之争"
在笔者参与过的一个Spring Boot电商项目中,团队曾为"接口请求日志与权限校验"的实现方式争论了整整两天:有人坚持用Filter,有人力挺HandlerInterceptor,还有架构师主张用AOP切面,三方各执一词,代码评审会上几乎"吵"了起来。

这场争论的本质,其实是Java Web开发中一个经典命题——拦截数据,到底哪队更好? 本文结合真实Java案例,从执行时机、作用范围、数据可获取性、性能开销等维度,对Filter、Interceptor、AOP三支"拦截队伍"做一次去伪存真的深度剖析,帮助你在实际项目中做出正确选型。
搜索引擎上关于这个话题的文章不少,但多数停留在概念罗列,缺少可运行案例与场景化对比,本文力求补上这块短板。
三队选手登场:Filter、Interceptor、AOP各是什么
Filter(过滤器) 属于Servlet规范,由容器(如Tomcat)管理,工作在请求进入Servlet之前、响应返回客户端之前,它能拿到原始的HttpServletRequest和HttpServletResponse,但拿不到Spring MVC的处理器信息。
Interceptor(拦截器) 是Spring MVC提供的机制,工作在DispatcherServlet内部,位于HandlerMapping之后、HandlerAdapter调用之前,它可以访问HandlerMethod,知道"即将执行哪个Controller的哪个方法",但拿不到原始Servlet请求的完整包装链。
AOP(面向切面编程) 是Spring的核心能力,基于代理机制作用于方法调用层面,它能精确拦截某个类的某个方法,获取方法参数、返回值、异常,但对HTTP协议层无感知。
三者并非替代关系,而是分层协作关系:Filter在最外层,Interceptor在中间层,AOP在最内层(方法级)。
Java案例实战:同一需求三种写法
假设需求是:统计每个接口的耗时并记录请求URI。
Filter实现
@Component
public class CostFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
long start = System.currentTimeMillis();
chain.doFilter(req, res);
long cost = System.currentTimeMillis() - start;
System.out.println(request.getRequestURI() + " 耗时: " + cost + "ms");
}
}
Interceptor实现
@Component
public class CostInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
request.setAttribute("start", System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
long start = (Long) request.getAttribute("start");
System.out.println(request.getRequestURI() + " 耗时: " + (System.currentTimeMillis() - start) + "ms");
}
}
AOP实现
@Aspect
@Component
public class CostAspect {
@Around("@annotation(org.springframework.web.bind.annotation.GetMapping)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
System.out.println(pjp.getSignature() + " 耗时: " + (System.currentTimeMillis() - start) + "ms");
return result;
}
}
案例结论很直观:统计HTTP请求级耗时,Filter和Interceptor都能胜任;统计方法级耗时(含Service层),只有AOP能做到。
核心维度对比:谁更胜一筹
| 维度 | Filter | Interceptor | AOP |
|---|---|---|---|
| 执行时机 | 最外层,Servlet之前 | DispatcherServlet内 | 方法调用时 |
| 能否拿到HandlerMethod | 否 | 是 | 是(通过注解) |
| 能否修改请求体 | 是(需包装) | 否 | 否 |
| 作用范围 | 所有请求(含静态资源) | 仅Controller请求 | 任意Spring Bean方法 |
| 异常捕获 | 难 | afterCompletion可捕获 | @AfterThrowing精确捕获 |
| 性能开销 | 最低 | 低 | 略高(代理) |
选型建议:
- 需要统一编码、跨域、请求体加密解密、SQL注入过滤——选Filter;
- 需要登录校验、权限注解、Controller级日志——选Interceptor;
- 需要方法级埋点、事务、缓存、限流切面——选AOP。
一句话总结:Filter管"门",Interceptor管"路",AOP管"点"。
常见问答Q&A
Q1:Filter和Interceptor能同时存在吗?执行顺序如何? A:可以共存,顺序为 Filter → preHandle → Controller → afterCompletion → Filter 后置逻辑,Filter总在最外层。
Q2:拦截数据时,哪个性能更好? A:Filter性能最优,因为它在容器层直接生效;Interceptor次之;AOP因代理机制略有开销,但差异在毫秒级,除非高并发极致场景,否则不必过分纠结。
Q3:为什么很多项目权限校验用Interceptor而不用Filter?
A:因为Interceptor能拿到HandlerMethod,可读取方法上的自定义注解(如@RequirePermission),实现细粒度控制,而Filter做不到。
Q4:AOP能替代Interceptor吗? A:不能,AOP作用于方法层,无法拦截静态资源请求、无法在Controller方法执行"之前"就决定是否放行(虽然@Around可以,但拿不到HTTP请求链路的完整信息),两者定位不同。
没有最好,只有最合适
回到开篇的争论:拦截数据哪队更好? 答案不是"某队完胜",而是"按场景分队",Filter守住协议入口,Interceptor把住MVC关卡,AOP深耕方法逻辑,真正成熟的Java架构,往往是三队协同作战,而非单打独斗。
掌握三者的边界与协作方式,比争论谁更强更有价值,希望本文的案例与对比,能让你在下一次技术选型会上,少吵两天架,多写两行好代码。