从 Servlet 到 WebMvcConfigurer:Java Web 与 Spring Boot 的进阶之旅
最近,我在翻看一些 Spring Boot 项目代码时,注意到某些类实现了 WebMvcConfigurer
接口。这让我突然意识到,自己对 Java Web 基础------尤其是 Servlet ------的了解其实非常浅薄。Servlet 中似乎有 Filter 和 Interceptor 两个概念,我一直觉得它们肯定有区别,但具体是什么区别呢?而 WebMvcConfigurer
又是什么?它隶属于哪个体系,和 Servlet 又有什么联系?带着这些疑问,我决定深入研究一番。
这次探索的契机是我在解决跨域问题时,发现可以通过 @CrossOrigin
注解或者定义一个实现了 WebMvcConfigurer
的类来处理。于是,我对 Servlet 相关的细节产生了浓厚的兴趣。接下来,我将详细介绍 Servlet、Filter、Interceptor 和 WebMvcConfigurer
的概念、区别以及它们在 Spring Boot 中的应用场景。
一、Servlet:Java Web 的基石
Servlet 是 Java Web 开发的核心组件,全称是 Server Applet ,它运行在服务器端,用于处理客户端的请求并生成响应。一个典型的 Servlet 生命周期包括初始化(init
)、处理请求(service
或具体的 doGet
、doPost
等方法)以及销毁(destroy
)。
在传统的 Java Web 开发中,Servlet 需要在 web.xml
中配置,例如:
xml
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
但在 Spring Boot 中,Servlet 的使用被高度抽象化,我们很少直接编写 Servlet,而是通过 Spring MVC 的 @Controller
或 @RestController
来处理请求。Spring MVC 的核心是一个特殊的 Servlet ------ DispatcherServlet
,它负责接收所有请求并分发给对应的控制器。
二、Filter:请求与响应的过滤器
Filter(过滤器)是 Servlet 规范的一部分,作用是在请求到达 Servlet 之前或响应返回客户端之前进行拦截和处理。Filter 的典型应用场景包括日志记录、权限验证、字符编码设置等。
Filter 的核心接口是 javax.servlet.Filter
,需要实现三个方法:
init
:初始化过滤器。doFilter
:执行过滤逻辑,可以通过chain.doFilter(request, response)
将请求传递给下一个过滤器或目标 Servlet。destroy
:销毁过滤器。
一个简单的 Filter 示例:
java
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter 初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("请求进入 Filter");
chain.doFilter(request, response); // 放行请求
System.out.println("响应离开 Filter");
}
@Override
public void destroy() {
System.out.println("Filter 销毁");
}
}
在 web.xml
中配置:
xml
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在 Spring Boot 中,可以通过 @Component
或 @Bean
将 Filter 注册到容器中,无需 web.xml
。
三、Interceptor:Spring MVC 的拦截器
Interceptor(拦截器)是 Spring MVC 的概念,不属于 Servlet 规范,而是 Spring 框架提供的更高级的请求拦截机制。Interceptor 作用于 DispatcherServlet
分发请求之后、控制器方法执行之前,主要用于更细粒度的逻辑处理,比如认证、日志、性能监控等。
Interceptor 的核心接口是 org.springframework.web.servlet.HandlerInterceptor
,需要实现三个方法:
preHandle
:在控制器方法执行前调用,返回true
放行,false
拦截。postHandle
:在控制器方法执行后、视图渲染前调用。afterCompletion
:在视图渲染完成后调用,常用于清理资源。
一个简单的 Interceptor 示例:
java
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("进入 Interceptor - preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
System.out.println("Interceptor - postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("Interceptor - afterCompletion");
}
}
四、Filter 与 Interceptor 的区别
虽然 Filter 和 Interceptor 都能拦截请求,但它们的定位和功能有明显差异:
-
所属体系:
- Filter 属于 Servlet 规范,由 Servlet 容器管理。
- Interceptor 属于 Spring MVC,由 Spring 容器管理。
-
拦截范围:
- Filter 作用于所有进入 Servlet 容器的请求(包括静态资源、Servlet 请求等)。
- Interceptor 只作用于 Spring MVC 处理的请求,不会拦截静态资源(如 CSS、JS)。
-
执行时机:
- Filter 在
DispatcherServlet
之前执行。 - Interceptor 在
DispatcherServlet
分发请求后、控制器方法执行前后执行。
- Filter 在
-
功能深度:
- Filter 更粗粒度,主要处理请求和响应的通用逻辑。
- Interceptor 更细粒度,可以访问 Spring 的上下文,操作
ModelAndView
等。
-
配置方式:
- Filter 通过
web.xml
或@Bean
配置。 - Interceptor 通过实现
WebMvcConfigurer
添加。
- Filter 通过
执行顺序示意图:
css
客户端请求 → Filter → DispatcherServlet → Interceptor → Controller → Interceptor → Filter → 客户端响应
五、WebMvcConfigurer:Spring MVC 的配置利器
WebMvcConfigurer
是 Spring MVC 提供的一个接口,用于自定义 Spring MVC 的配置。它隶属于 Spring Framework 的 org.springframework.web.servlet.config
包,主要用于扩展 DispatcherServlet
的功能,而不覆盖默认配置。
常见的配置方法包括:
addInterceptors
:添加自定义拦截器。addCorsMappings
:配置跨域支持。addViewControllers
:添加视图控制器。configureMessageConverters
:自定义消息转换器。
一个解决跨域问题的示例:
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 匹配所有路径
.allowedOrigins("http://localhost:8080") // 允许的源
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的方法
.allowCredentials(true); // 允许携带凭证
}
}
相比 @CrossOrigin
注解,WebMvcConfigurer
的优势在于可以全局配置跨域规则,而 @CrossOrigin
通常作用于单个控制器或方法。
WebMvcConfigurer 的上层架构
WebMvcConfigurer
是 Spring MVC 配置体系的一部分,其上层是 WebMvcConfigurationSupport
类。如果直接继承 WebMvcConfigurationSupport
,会覆盖 Spring Boot 的默认 MVC 配置,因此推荐使用 WebMvcConfigurer
接口。
等价的替代方案:
- Spring Boot 自动配置 :Spring Boot 通过
application.properties
或application.yml
提供了一些简化的配置,例如静态资源路径、跨域等。 - 直接操作 DispatcherServlet:极少使用,过于底层。
六、跨域问题与 Servlet 的联系
跨域问题(CORS)是现代 Web 开发中的常见需求。在 Servlet 层面,可以通过 Filter 手动设置响应头来解决:
java
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
resp.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
}
但在 Spring Boot 中,使用 WebMvcConfigurer
或 @CrossOrigin
更符合框架的约定,代码更优雅,管理更集中。
七、总结与反思
通过这次学习,我终于弄清楚了 Servlet、Filter、Interceptor 和 WebMvcConfigurer
的关系:
- Servlet 是 Java Web 的核心,Spring MVC 的
DispatcherServlet
是其现代演绎。 - Filter 是 Servlet 规范的通用拦截机制,适用于全局请求处理。
- Interceptor 是 Spring MVC 的专属拦截器,专注于控制器层逻辑。
- WebMvcConfigurer 是 Spring MVC 的配置接口,提供了灵活的扩展点,比如跨域配置。