我们来探讨一下 Spring MVC 是如何建立在 Servlet API 之上的,看看它是怎样利用 Servlet API 的组件和机制来运作的:
-
核心入口点:
DispatcherServlet就是一个HttpServlet- 这是最根本的联系。Spring MVC 的核心控制器
DispatcherServlet直接或间接继承自javax.servlet.http.HttpServlet。 - 这意味着
DispatcherServlet拥有标准 Servlet 的所有生命周期方法(init(),service(),destroy())并且可以被 Servlet 容器(如 Tomcat)管理。 - 如何集成:
web.xml(传统方式): 需要在web.xml文件中声明DispatcherServlet并为其配置 URL 映射(<servlet>和<servlet-mapping>标签)。Servlet 容器启动时会读取这个配置,实例化DispatcherServlet,并在匹配的 URL 请求到达时调用其service()方法。- Java 配置 : 通过实现
WebApplicationInitializer接口(通常是继承AbstractAnnotationConfigDispatcherServletInitializer),我们可以以编程方式向ServletContext注册DispatcherServlet实例及其映射。这利用了 Servlet 3.0+ 规范提供的ServletContainerInitializer机制,在容器启动时自动发现并执行你的配置类。这本质上是使用 Servlet API 提供的编程接口来替代web.xml。
- 关键点: 无论哪种方式,最终都是 Servlet 容器根据 Servlet API 规范来加载、初始化并调用
DispatcherServlet。
- 这是最根本的联系。Spring MVC 的核心控制器
-
请求处理流程始于 Servlet API 对象
- 当一个 HTTP 请求到达 Servlet 容器并被映射到
DispatcherServlet时,容器会:- 创建
HttpServletRequest对象,封装所有关于这个 HTTP 请求的信息(URL, 方法, 头, 参数, 请求体等)。 - 创建
HttpServletResponse对象,用于构建将要发送回客户端的 HTTP 响应。 - 调用
DispatcherServlet的service()方法(或者根据 HTTP 方法调用doGet(),doPost()等),并将这两个 Servlet API 对象作为参数传入。
- 创建
- Spring MVC 的接管:
DispatcherServlet接收到这两个原始对象后,不会直接在自身代码中处理业务逻辑。它扮演的是**前端控制器(Front Controller)**的角色。
- 当一个 HTTP 请求到达 Servlet 容器并被映射到
-
封装与抽象
HttpServletRequest和HttpServletResponseDispatcherServlet内部会将原始的HttpServletRequest和HttpServletResponse传递给它的协作组件(HandlerMapping, HandlerAdapter 等)。- 参数提取与绑定: Spring MVC 提供了强大的数据绑定机制。它会检查 Controller 方法的参数签名,并使用内部的
HandlerMethodArgumentResolver实现来从HttpServletRequest中提取数据(如请求参数、路径变量、请求头、请求体)并将其转换、绑定到方法参数上(如@RequestParam,@PathVariable,@RequestHeader,@RequestBody, 或直接绑定到 POJO)。这个过程隐藏了直接操作HttpServletRequest.getParameter()或request.getInputStream()的复杂性。 - 响应构建: 同样,Controller 方法的返回值(如
String代表视图名,ModelAndView, 或带有@ResponseBody的对象)会被HandlerMethodReturnValueHandler处理。最终,这些处理器会利用传入的HttpServletResponse来设置状态码、响应头,并将响应体(渲染后的 HTML、JSON/XML 数据等)写入response.getOutputStream()或response.getWriter()。Spring MVC 提供了视图解析、消息转换等机制,简化了构建响应的过程。 - 直接访问(可选): 尽管 Spring MVC 提供了抽象,但如果你确实需要原始的 Servlet API 对象,可以直接在 Controller 方法参数中声明
HttpServletRequest或HttpServletResponse,Spring 会自动将它们注入。
-
利用
ServletContext存储应用上下文- Spring 框架(不仅仅是 Spring MVC)通常需要一个全局的应用上下文 (
ApplicationContext) 来管理 Bean(如 Service, Repository 等)。对于 Web 应用,这通常是WebApplicationContext。 ContextLoaderListener: 这是一个标准的javax.servlet.ServletContextListener。通常配置在web.xml或通过WebApplicationInitializer注册。当 Servlet 容器初始化 Web 应用(创建ServletContext)时,会触发这个 Listener 的contextInitialized()方法。- 作用:
ContextLoaderListener在contextInitialized()方法中创建 Spring 的根应用上下文 (Root WebApplicationContext),并将其存储为ServletContext的一个属性(通常使用WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE作为键)。 - 共享: 这样,
DispatcherServlet(以及应用中的其他 Servlet 或 Filter)就可以通过ServletContext.getAttribute()方法访问到这个共享的根上下文,从而访问到整个应用共享的 Bean。 DispatcherServlet通常还会创建自己的子上下文,包含与 Web 相关的 Bean(Controller, ViewResolver 等),这个子上下文可以访问根上下文中的 Bean。
- Spring 框架(不仅仅是 Spring MVC)通常需要一个全局的应用上下文 (
-
利用 Servlet Filter 机制
- Servlet API 提供了 Filter (
javax.servlet.Filter) 机制,允许在请求到达 Servlet 之前或响应离开 Servlet 之后进行拦截和处理。 - Spring 大量使用 Filter 来实现横切关注点:
CharacterEncodingFilter: 统一请求和响应的字符编码。HiddenHttpMethodFilter: 支持在 HTML 表单中使用 PUT, DELETE 等方法。- Spring Security: 安全认证和授权的核心就是通过一系列 Filter Chain 实现的。
- 这些 Filter 是标准的 Servlet Filter,它们的配置和生命周期管理都遵循 Servlet API 规范。它们在
DispatcherServlet之前或之后处理HttpServletRequest和HttpServletResponse。
- Servlet API 提供了 Filter (
总结来说,Spring MVC 建立在 Servlet API 之上的方式体现在:
- 核心组件是 Servlet:
DispatcherServlet是一个标准的HttpServlet。 - 遵循 Servlet 生命周期:
DispatcherServlet的加载、初始化和销毁由 Servlet 容器管理。 - 接收 Servlet API 对象:
DispatcherServlet通过其service方法接收容器传入的HttpServletRequest和HttpServletResponse。 - 基于 Servlet API 对象进行抽象: Spring MVC 提供了更高级的 API 来访问请求数据和构建响应,但底层操作的仍然是 Servlet API 对象。
- 利用 ServletContext: 通过
ServletContextListener和ServletContext属性来管理和共享 Spring 的WebApplicationContext。 - 集成 Servlet Filter: 使用标准的 Servlet Filter 实现各种横切功能。
Spring MVC 巧妙地利用了 Servlet API 提供的基础构件和扩展点,在其上构建了一个功能丰富、结构清晰、易于使用的 Web 框架,大大提高了开发效率。它没有重新发明轮子,而是站在了巨人的肩膀上。
868

被折叠的 条评论
为什么被折叠?



