资讯详情

Servlet与Spring三大组件:Filter、Listener和Interceptor详解

📅 2026/10/31 5:42:32 | 华诺云谱 👁 阅读
Servlet与Spring三大组件:Filter、Listener和Interceptor详解
1. 从Servlet到Spring三大组件的本质区别在Java Web开发中Filter、Listener和Interceptor这三个概念经常让开发者困惑。我见过不少团队因为错误使用这些组件导致性能问题甚至安全漏洞。今天我们就从底层原理出发彻底讲清楚它们的差异。1.1 组件定位与生命周期Filter是Servlet规范定义的过滤器它的工作时机在Servlet容器层面。当请求进入容器后会先经过Filter链处理最后才到达Servlet。典型的Filter实现是这样的public class AuthFilter implements Filter { Override public void init(FilterConfig config) { // 初始化逻辑 } Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { // 前置处理 HttpServletRequest request (HttpServletRequest) req; if (!checkAuth(request)) { ((HttpServletResponse)res).sendError(403); return; } chain.doFilter(req, res); // 放行到下一个Filter或Servlet // 后置处理 } }Listener则是事件监听器主要监听ServletContext、HttpSession和ServletRequest的生命周期事件。比如统计在线人数WebListener public class OnlineCounter implements HttpSessionListener { private static AtomicInteger count new AtomicInteger(); Override public void sessionCreated(HttpSessionEvent se) { count.incrementAndGet(); } Override public void sessionDestroyed(HttpSessionEvent se) { count.decrementAndGet(); } }Interceptor是Spring MVC框架层面的拦截器基于AOP思想实现。它只能在Controller方法前后进行拦截public class LogInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) { log.info(请求开始: {}, req.getRequestURI()); return true; // 继续执行 } Override public void postHandle(/*...*/) { // 视图渲染前执行 } Override public void afterCompletion(/*...*/) { // 请求完成后的清理 } }1.2 核心差异对比通过一个表格直观对比三者的关键区别特性FilterListenerInterceptor规范层级Servlet规范Servlet规范Spring框架作用范围所有HTTP请求容器事件Controller请求执行顺序web.xml定义顺序无顺序依赖配置定义顺序依赖注入不支持不支持支持Spring DI典型场景编码转换、安全过滤统计、初始化权限检查、日志记录关键经验Filter适合做通用的、与业务无关的请求处理Interceptor适合处理与业务逻辑相关的横切关注点Listener则用于响应系统事件。1.3 执行流程深度解析当请求到达Spring Web应用时完整的处理流程是这样的容器接收到HTTP请求依次执行匹配的Filter字符编码、XSS过滤等请求进入Spring MVC框架执行Interceptor的preHandle方法调用Controller方法执行Interceptor的postHandle方法视图渲染执行Interceptor的afterCompletion方法返回响应时再次经过Filter链这个流程中容易出现的问题点是执行顺序混乱。我曾遇到一个案例开发者在Filter中设置了响应头但在Interceptor中又修改了这些头信息导致最终结果不符合预期。正确的做法是保持关注点分离——Filter处理协议层问题Interceptor处理业务层问题。2. 实战场景下的组件选型2.1 必须使用Filter的场景跨域处理是最典型的Filter应用场景。虽然Spring提供了CrossOrigin注解但在微服务架构中更推荐使用统一的Filterpublic class CorsFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { HttpServletResponse response (HttpServletResponse) res; response.setHeader(Access-Control-Allow-Origin, *); response.setHeader(Access-Control-Allow-Methods, POST, GET, OPTIONS, DELETE); response.setHeader(Access-Control-Max-Age, 3600); response.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); if (OPTIONS.equalsIgnoreCase(((HttpServletRequest) req).getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } }其他适合Filter的场景包括请求/响应日志记录特别是需要记录原始二进制数据时全局字符编码设置防止CSRF攻击的基础防护流量限制和QoS控制2.2 Interceptor的黄金使用场景权限验证是Interceptor的经典用例。相比Filter它可以利用Spring的依赖注入访问Service层组件public class AuthInterceptor implements HandlerInterceptor { Autowired private AuthService authService; Override public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) { String token req.getHeader(X-Auth-Token); if (!authService.validateToken(token)) { throw new UnauthorizedException(无效的认证令牌); } return true; } }其他Interceptor适用场景API调用频率限制业务操作日志记录接口耗时监控数据权限过滤如多租户隔离2.3 Listener的特殊价值系统初始化是Listener的重要用途。比如在应用启动时加载缓存WebListener public class CacheLoader implements ServletContextListener { Override public void contextInitialized(ServletContextEvent sce) { RedisCache.loadAllProducts(); RedisCache.loadUserBlacklist(); } }同样适合Listener的场景统计在线用户数资源文件的动态加载应用关闭时的资源释放会话超时处理避坑指南Listener中不要执行耗时操作否则会拖慢应用启动速度。对于需要长时间初始化的任务应该使用异步方式处理。3. 高级应用与性能优化3.1 组件注册的现代方式传统XML配置方式正在被注解取代。Spring Boot中推荐这样注册组件Configuration public class WebConfig implements WebMvcConfigurer { // 注册Interceptor Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()) .addPathPatterns(/api/**) .excludePathPatterns(/static/**); } // 注册Filter Bean public FilterRegistrationBeanCorsFilter corsFilter() { FilterRegistrationBeanCorsFilter bean new FilterRegistrationBean(); bean.setFilter(new CorsFilter()); bean.addUrlPatterns(/*); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置最高优先级 return bean; } }3.2 执行顺序控制技巧当多个Filter和Interceptor共存时顺序控制至关重要Filter的顺序由FilterRegistrationBean的order属性或web.xml中的定义顺序决定Interceptor的顺序通过InterceptorRegistry的addInterceptor调用顺序控制最佳实践是明确设置order值避免隐式依赖一个典型的顺序配置示例// 安全Filter应该最先执行 Bean public FilterRegistrationBeanSecurityFilter securityFilter() { FilterRegistrationBeanSecurityFilter bean new FilterRegistrationBean(); bean.setFilter(new SecurityFilter()); bean.setOrder(Ordered.HIGHEST_PRECEDENCE 1); return bean; } // 日志Interceptor应该最早记录请求 Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()).order(1); registry.addInterceptor(new AuthInterceptor()).order(2); }3.3 性能优化要点Filter优化避免在Filter中做复杂业务逻辑对于静态资源应该在web.xml或FilterRegistrationBean中排除考虑使用WebFilter的asyncSupported属性支持异步处理Interceptor优化preHandle方法尽量轻量复杂检查可以放到Controller中使用路径匹配减少不必要的拦截考虑使用HandlerMethod参数精确控制拦截范围Listener优化避免在Listener中保存大对象对于高频事件如ServletRequest事件考虑使用弱引用确保事件处理逻辑是线程安全的4. 常见问题排查指南4.1 典型问题与解决方案问题1Filter未生效检查web.xml配置或FilterRegistrationBean是否正确确认urlPatterns匹配了目标路径查看是否有更高优先级的Filter提前终止了链问题2Interceptor不执行确认请求是否经过DispatcherServlet检查路径匹配模式是否正确查看preHandle是否返回了false问题3Listener事件重复触发检查是否重复注册了Listener确认是否是正常的生命周期事件对于Spring环境避免同时使用WebListener和Component4.2 调试技巧使用调试断点在Filter的doFilter方法入口在Interceptor的三个方法入口在Listener的事件回调方法日志记录建议// 在Filter中记录请求信息 log.debug(Filter处理请求: {}?{}, req.getRequestURI(), req.getQueryString()); // 在Interceptor中记录处理时间 long start System.currentTimeMillis(); try { return true; } finally { log.info(请求处理耗时: {}ms, System.currentTimeMillis()-start); }Spring Actuator端点/filters 查看已注册的Filter/mappings 查看URL映射关系4.3 设计模式应用责任链模式在Filter和Interceptor中都有体现。我们可以利用这点实现灵活的处理流程// 自定义Filter链 public class CompositeFilter implements Filter { private ListFilter filters; Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { new VirtualFilterChain(chain, filters).doFilter(req, res); } private static class VirtualFilterChain implements FilterChain { private final FilterChain originalChain; private final IteratorFilter iterator; public VirtualFilterChain(FilterChain chain, ListFilter filters) { this.originalChain chain; this.iterator filters.iterator(); } Override public void doFilter(ServletRequest req, ServletResponse res) { if (iterator.hasNext()) { iterator.next().doFilter(req, res, this); } else { originalChain.doFilter(req, res); } } } }对于InterceptorSpring已经内置了类似的链式处理机制我们只需要关注单个拦截器的实现即可。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑