SpringBoot拦截器(Interceptor)深度解析与实践指南

SpringBoot拦截器(Interceptor)深度解析与实践指南

springboot-guide SpringBoot2.0+从入门到实战! springboot-guide 项目地址: https://gitcode.com/gh_mirrors/sp/springboot-guide

一、拦截器基础概念

拦截器(Interceptor)是Spring框架中一个非常重要的组件,它基于AOP(面向切面编程)思想实现,主要用于在请求处理的不同阶段进行拦截和处理。与Servlet过滤器(Filter)类似,但拦截器提供了更精细的控制粒度。

拦截器与过滤器的本质区别

  1. 作用层面不同

    • 过滤器工作在Servlet层面,属于JavaEE标准
    • 拦截器工作在Spring MVC层面,属于Spring框架特性
  2. 功能侧重点不同

    • 过滤器更关注请求的"过滤"(如字符编码设置、安全过滤等)
    • 拦截器更关注请求处理流程的"干预"(如权限验证、日志记录等)
  3. 执行时机不同

    • 过滤器在Servlet容器接收到请求后立即执行
    • 拦截器在DispatcherServlet处理请求的过程中执行

二、拦截器核心方法详解

Spring拦截器主要通过实现HandlerInterceptor接口或继承HandlerInterceptorAdapter类来实现,需要重写三个核心方法:

1. preHandle方法

public boolean preHandle(HttpServletRequest request,
                        HttpServletResponse response,
                        Object handler)

执行时机:在Controller方法执行之前调用
返回值意义

  • 返回true:继续执行后续拦截器和Controller方法
  • 返回false:中断执行流程,不会继续执行后续拦截器和Controller

典型应用场景

  • 权限校验
  • 登录检查
  • 请求参数预处理

2. postHandle方法

public void postHandle(HttpServletRequest request,
                      HttpServletResponse response,
                      Object handler,
                      ModelAndView modelAndView)

执行时机:在Controller方法执行之后,视图渲染之前调用
注意事项

  • 只有preHandle返回true时才会执行
  • 可以对ModelAndView进行修改

典型应用场景

  • 向视图添加公共模型数据
  • 统一处理返回结果

3. afterCompletion方法

public void afterCompletion(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           Exception ex)

执行时机:在整个请求完成之后调用(视图渲染完成后)
注意事项

  • 无论preHandle返回true还是false都会执行
  • 适合进行资源清理工作

典型应用场景

  • 记录请求完成日志
  • 资源释放
  • 性能监控

三、实战:自定义拦截器开发

1. 日志记录拦截器实现

public class LogInterceptor extends HandlerInterceptorAdapter {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        log.info("请求开始: URL={}, 时间={}", 
                request.getRequestURL(), startTime);
        return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, 
                              HttpServletResponse response, 
                              Object handler, 
                              Exception ex) {
        long startTime = (Long)request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        log.info("请求完成: URL={}, 耗时={}ms", 
                request.getRequestURL(), (endTime - startTime));
    }
}

2. 旧URL重定向拦截器实现

public class OldUrlRedirectInterceptor extends HandlerInterceptorAdapter {
    
    @Override
    public boolean preHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler) throws Exception {
        // 获取请求路径
        String requestURI = request.getRequestURI();
        
        // 如果是旧URL则重定向
        if("/admin/oldLogin".equals(requestURI)) {
            String contextPath = request.getContextPath();
            response.sendRedirect(contextPath + "/admin/login");
            return false; // 中断后续处理
        }
        
        return true;
    }
}

3. 管理员权限校验拦截器实现

public class AdminAuthInterceptor extends HandlerInterceptorAdapter {
    
    @Override
    public boolean preHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler) throws Exception {
        HttpSession session = request.getSession();
        Object adminUser = session.getAttribute("adminUser");
        
        if(adminUser == null) {
            // 未登录,跳转到登录页
            response.sendRedirect(request.getContextPath() + "/admin/login");
            return false;
        }
        
        return true;
    }
}

四、拦截器配置详解

在Spring Boot中配置拦截器需要实现WebMvcConfigurer接口:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 1. 添加日志拦截器,拦截所有请求
        registry.addInterceptor(new LogInterceptor());
        
        // 2. 添加旧URL重定向拦截器,只拦截特定路径
        registry.addInterceptor(new OldUrlRedirectInterceptor())
                .addPathPatterns("/admin/oldLogin");
        
        // 3. 添加管理员权限拦截器,拦截/admin下所有请求
        //    但排除登录相关请求
        registry.addInterceptor(new AdminAuthInterceptor())
                .addPathPatterns("/admin/**")
                .excludePathPatterns("/admin/login", "/admin/doLogin");
    }
}

配置方法说明

  • addInterceptor():注册拦截器实例
  • addPathPatterns():指定拦截路径(支持Ant风格)
  • excludePathPatterns():指定排除路径

五、拦截器执行流程深度解析

1. 单个拦截器执行流程

preHandle → Controller → postHandle → 视图渲染 → afterCompletion

2. 多个拦截器执行流程

假设有Interceptor1和Interceptor2两个拦截器,执行顺序为:

Interceptor1.preHandle → 
Interceptor2.preHandle → 
Controller → 
Interceptor2.postHandle → 
Interceptor1.postHandle → 
视图渲染 → 
Interceptor2.afterCompletion → 
Interceptor1.afterCompletion

关键点

  • preHandle按配置顺序执行
  • postHandle按配置逆序执行
  • afterCompletion按配置逆序执行

六、最佳实践与常见问题

1. 性能优化建议

  • 在preHandle中进行轻量级检查
  • 避免在拦截器中执行耗时操作
  • 合理设计拦截路径,避免不必要的拦截

2. 常见问题解决方案

问题1:拦截器不生效
排查步骤

  1. 检查是否添加了@Configuration注解
  2. 确认拦截路径是否正确
  3. 查看是否有其他配置覆盖了拦截器配置

问题2:静态资源被拦截
解决方案

registry.addInterceptor(new MyInterceptor())
        .addPathPatterns("/**")
        .excludePathPatterns("/static/**", "/resources/**");

七、高级应用场景

1. 接口限流拦截器

public class RateLimitInterceptor extends HandlerInterceptorAdapter {
    
    private RateLimiter rateLimiter = RateLimiter.create(100); // 每秒100个请求
    
    @Override
    public boolean preHandle(HttpServletRequest request,
                          HttpServletResponse response,
                          Object handler) {
        if(!rateLimiter.tryAcquire()) {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            return false;
        }
        return true;
    }
}

2. 多租户数据隔离拦截器

public class TenantInterceptor extends HandlerInterceptorAdapter {
    
    @Override
    public boolean preHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler) {
        String tenantId = request.getHeader("X-Tenant-ID");
        if(StringUtils.isNotBlank(tenantId)) {
            TenantContext.setCurrentTenant(tenantId);
        }
        return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request,
                              HttpServletResponse response,
                              Object handler,
                              Exception ex) {
        TenantContext.clear();
    }
}

八、总结与扩展思考

Spring Boot拦截器是处理横切关注点的强大工具,合理使用可以:

  • 实现统一的权限控制
  • 进行请求日志记录
  • 处理全局异常
  • 实现接口限流
  • 完成多租户隔离等复杂场景

扩展思考方向

  1. 如何结合注解实现更灵活的拦截控制?
  2. 拦截器与Spring AOP如何配合使用?
  3. 在微服务架构中,拦截器与网关过滤器如何分工协作?

通过本文的详细讲解和实战示例,相信你已经掌握了Spring Boot拦截器的核心原理和实际应用方法。在实际项目中,可以根据业务需求灵活组合各种拦截器,构建强大的请求处理管道。

springboot-guide SpringBoot2.0+从入门到实战! springboot-guide 项目地址: https://gitcode.com/gh_mirrors/sp/springboot-guide

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方玉蜜United

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值