Filter、Interceptor、Spring AOP 的执行顺序详解

在Spring Boot应用开发中,Filter、Interceptor和Spring AOP是三个重要的概念,它们都可以在请求处理的不同阶段对业务逻辑进行增强。了解它们的执行顺序对于正确实现功能至关重要。本文将详细解析这三个组件的执行顺序及其应用场景。

一、核心概念介绍

1.1 Filter(过滤器)

  • 定义:基于Servlet规范的过滤器,运行在容器级别
  • 特点:在请求到达DispatcherServlet之前执行
  • 应用场景:权限验证、字符编码设置、日志记录等
  • 生命周期:由Web容器管理,随应用启动而初始化

1.2 Interceptor(拦截器)

  • 定义:Spring MVC框架提供的拦截机制
  • 特点:在Controller方法执行前后执行
  • 应用场景:登录验证、参数校验、统一响应处理等
  • 依赖关系:依赖于Spring MVC的DispatcherServlet

1.3 Spring AOP(面向切面编程)

  • 定义:基于代理模式的横切关注点实现
  • 特点:可以在方法调用前后、异常抛出时执行通知
  • 应用场景:事务管理、缓存、安全控制、性能监控等
  • 实现原理:通过动态代理实现方法级别的拦截

二、执行顺序分析

2.1 完整执行流程图解

这个时序图清晰地展示了 Spring Web 请求处理的完整流程:

复制代码
客户端请求 → Filter Chain(过滤器链处理)
→ DispatcherServlet(Spring MVC 前端控制器)
→ Interceptor preHandle(拦截器前置处理)
→ Controller(控制器方法执行)
→ Spring AOP(切面编程处理)
→ Interceptor postHandle(拦截器后置处理)
→ View Rendering(视图渲染)
→ Interceptor afterCompletion(拦截器完成处理)
→ Filter Chain → 客户端响应

2.2 详细执行顺序对比

执行阶段 组件 执行时机
1 Filter doFilter() - 请求预处理
2 Interceptor preHandle() - 控制器方法前
3 Spring AOP @Before, @Around (before) - 业务方法前
4 Business Logic 实际业务方法执行
5 Spring AOP @After, @AfterReturning, @Around (after) - 业务方法后
6 Interceptor postHandle() - 控制器方法后,视图渲染前
7 View 视图渲染
8 Interceptor afterCompletion() - 请求完成后
9 Filter doFilter() - 响应后处理

2.3 异常情况下的执行顺序

当发生异常时:

  • 如果在Controller层抛出异常:AOP的@After依然会执行
  • 如果在Controller层抛出异常:AOP的@AfterThrowing会捕获异常
  • Interceptor的afterCompletion()方法会接收到异常信息
  • Filter的后续过滤器链会被中断

三、实际应用示例

3.1 Filter实现示例

java 复制代码
@Component
public class CustomFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        System.out.println("Filter: 请求开始处理");
        
        // 添加自定义逻辑
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String startTime = String.valueOf(System.currentTimeMillis());
        httpRequest.setAttribute("startTime", startTime);
        
        chain.doFilter(request, response);  // 继续执行
        
        System.out.println("Filter: 响应处理完成");
    }
}

3.2 Interceptor实现示例

java 复制代码
@Component
public class CustomInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        System.out.println("Interceptor: preHandle - 控制器执行前");
        
        // 权限检查逻辑
        String token = request.getHeader("Authorization");
        if (token == null || !isValidToken(token)) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, 
                          HttpServletResponse response, 
                          Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor: postHandle - 控制器执行后");
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, 
                              HttpServletResponse response, 
                              Object handler, Exception ex) throws Exception {
        System.out.println("Interceptor: afterCompletion - 请求完成");
        if (ex != null) {
            System.out.println("Interceptor: 捕获到异常: " + ex.getMessage());
        }
    }
}

3.3 Spring AOP实现示例

java 复制代码
@Aspect
@Component
public class CustomAspect {
    
    @Around("@annotation(com.example.annotation.LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("AOP: Around - 方法执行前");
        
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();  // 执行目标方法
            System.out.println("AOP: Around - 方法执行成功");
        } catch (Exception e) {
            System.out.println("AOP: Around - 捕获异常: " + e.getMessage());
            throw e;
        }
        
        long endTime = System.currentTimeMillis();
        System.out.println("AOP: 方法执行耗时: " + (endTime - startTime) + "ms");
        
        return result;
    }
    
    @Before("execution(* com.example.controller.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("AOP: Before - 方法执行前");
    }
    
    @After("execution(* com.example.controller.*.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        System.out.println("AOP: After - 方法执行后(无论成功失败)");
    }
}

四、最佳实践建议

4.1 使用场景选择指南

  • Filter适用于:需要在最外层进行统一处理的场景,如跨域处理、全局安全检查
  • Interceptor适用于:与Spring MVC相关的处理,如用户身份验证、请求参数预处理
  • Spring AOP适用于:业务逻辑层面的横切关注点,如事务管理、缓存、日志

4.2 性能优化考虑

  • 尽量减少Filter的数量,避免过多的过滤器链
  • 合理设计Interceptor,避免重复的验证逻辑
  • AOP切点表达式要精确,避免不必要的代理创建

4.3 错误处理策略

  • Filter中的错误通常影响整个请求流程
  • Interceptor可以阻止请求继续执行到Controller
  • AOP适合进行细粒度的异常处理和恢复

通过理解这三种技术的执行顺序和适用场景,我们可以构建更加健壮和高效的Spring Boot应用程序。记住,合理的选择和组合使用这些技术,可以让我们的代码结构更清晰,维护更容易。

相关推荐
想用offer打牌2 小时前
一站式了解Spring AI Alibaba的Memory机制
java·人工智能·后端·spring·chatgpt·系统架构
打工的小王2 小时前
Langchain4j(二)RAG知识库
java·后端·ai·语言模型
李慕婉学姐2 小时前
【开题答辩过程】以《基于springcloud的空气质量监控管理系统》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
后端·spring·spring cloud
Remember_9932 小时前
【数据结构】Java对象比较全解析:从equals到Comparable与Comparator,再到PriorityQueue应用
java·开发语言·数据结构·算法·leetcode·哈希算法
沛沛老爹2 小时前
从Web到AI:多模态Agent Skills生态系统实战(Java+Vue构建跨模态智能体)
java·前端·vue.js·人工智能·rag·企业转型
a努力。3 小时前
饿了么Java面试被问:一致性哈希的虚拟节点和数据迁移
java·chrome·后端·websocket·面试·职场和发展
把csdn当日记本的菜鸡3 小时前
Java设计模式简单入门
java·开发语言·设计模式
0和1的舞者3 小时前
非力扣hot100-二叉树专题-刷题笔记(一)
笔记·后端·算法·leetcode·职场和发展·知识