SpringMVC 请求处理流程详解:从 DispatcherServlet 到 ViewResolver
各位看官,今天咱们来聊聊SpringMVC,这可是Java Web开发界的老朋友了。说起它,就好像一位精明强干的管家,默默地打理着我们Web应用的方方面面,让咱们这些程序员可以专心致志地写业务逻辑,不用操心那些繁琐的请求处理。
既然是管家,那肯定得了解它的工作流程。今天,咱们就来扒一扒SpringMVC的请求处理流程,从DispatcherServlet这位总调度员,一直追踪到ViewResolver这位视图解析大师,保证让各位看得明白,学得透彻。
一、DispatcherServlet:总调度员闪亮登场
SpringMVC的核心,非DispatcherServlet莫属。它就像一个总调度员,接收所有进入我们Web应用的HTTP请求,然后根据请求的URL,将请求分发给合适的处理器。
简单来说,DispatcherServlet扮演了中央控制器的角色。它拦截所有进入应用的请求,然后委托给Spring MVC的其他组件来处理请求。
1.1 DispatcherServlet 的初始化
DispatcherServlet是一个Servlet,所以它的生命周期是由Servlet容器(比如Tomcat)管理的。当Web应用启动时,Servlet容器会加载DispatcherServlet,并调用它的init()
方法进行初始化。
在init()
方法中,DispatcherServlet会做一些关键的事情:
- 加载Spring配置: DispatcherServlet会根据配置文件(通常是XML文件或者Java配置类)创建一个WebApplicationContext,这个Context是Spring容器的扩展,它包含了所有Spring管理的bean,包括Controller、Service等等。
- 初始化各个组件: DispatcherServlet会从WebApplicationContext中获取各种组件,比如HandlerMapping、HandlerAdapter、ViewResolver等等。这些组件是处理请求的关键。
1.2 web.xml 配置
想要让DispatcherServlet工作起来,需要在web.xml
文件中进行配置。
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-name>
:DispatcherServlet的名称,可以自定义。<servlet-class>
:DispatcherServlet的类名,固定为org.springframework.web.servlet.DispatcherServlet
。<init-param>
:初始化参数,contextConfigLocation
指定Spring MVC配置文件的路径。<load-on-startup>
:Servlet启动顺序,值越小,启动越早。<url-pattern>
:拦截的URL模式,/
表示拦截所有请求。
1.3 请求到达
当用户发起一个HTTP请求时,Servlet容器会根据web.xml
中的配置,将请求交给DispatcherServlet处理。DispatcherServlet的doDispatch()
方法是处理请求的核心。
二、请求处理流程:一步一个脚印
DispatcherServlet 接收到请求后,会按照以下步骤进行处理:
- 查找HandlerMapping: DispatcherServlet会遍历WebApplicationContext中所有的HandlerMapping,找到能够处理当前请求的HandlerMapping。HandlerMapping的作用是根据请求的URL,找到对应的Handler(通常是一个Controller方法)。
- 获取HandlerExecutionChain: HandlerMapping找到Handler后,会返回一个HandlerExecutionChain,它包含了Handler和一些拦截器(Interceptor)。
- 查找HandlerAdapter: DispatcherServlet会遍历WebApplicationContext中所有的HandlerAdapter,找到能够处理当前Handler的HandlerAdapter。HandlerAdapter的作用是适配Handler,将Handler的调用方式转换为DispatcherServlet可以理解的方式。
- 执行Handler: HandlerAdapter会调用Handler,执行具体的业务逻辑。Handler执行完毕后,会返回一个ModelAndView对象,它包含了视图名称和模型数据。
- 处理异常: 如果在请求处理过程中发生异常,DispatcherServlet会查找WebApplicationContext中所有的HandlerExceptionResolver,找到能够处理当前异常的HandlerExceptionResolver。HandlerExceptionResolver的作用是将异常转换为ModelAndView对象。
- 查找ViewResolver: DispatcherServlet会遍历WebApplicationContext中所有的ViewResolver,找到能够解析当前视图名称的ViewResolver。ViewResolver的作用是将视图名称转换为View对象。
- 渲染视图: ViewResolver找到View对象后,DispatcherServlet会调用View对象的
render()
方法,将模型数据渲染到响应中。
可以用一张表格更清晰地展示这个流程:
步骤 | 组件 | 作用 |
---|---|---|
1 | HandlerMapping | 根据请求URL查找对应的Handler(Controller方法) |
2 | HandlerExecutionChain | 包含Handler和拦截器 |
3 | HandlerAdapter | 适配Handler,将Handler的调用方式转换为DispatcherServlet可以理解的方式 |
4 | Handler | 执行具体的业务逻辑 |
5 | HandlerExceptionResolver | 处理请求过程中发生的异常,将异常转换为ModelAndView对象 |
6 | ViewResolver | 将视图名称转换为View对象 |
7 | View | 将模型数据渲染到响应中 |
三、HandlerMapping:找到对的人
HandlerMapping就像一个媒婆,它的任务是根据请求的URL,找到能够处理这个请求的Handler。SpringMVC提供了多种HandlerMapping,常用的有:
- RequestMappingHandlerMapping: 基于
@RequestMapping
注解的HandlerMapping,也是最常用的。 - BeanNameUrlHandlerMapping: 基于Bean名称的HandlerMapping,不常用。
- SimpleUrlHandlerMapping: 基于URL和Bean名称的映射,不常用。
3.1 RequestMappingHandlerMapping 的使用
RequestMappingHandlerMapping
通过扫描带有@Controller
注解的类,以及带有@RequestMapping
注解的方法,来建立URL和Handler的映射关系。
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/list")
public String list(Model model) {
// ...
return "user/list";
}
@RequestMapping("/detail/{id}")
public String detail(@PathVariable("id") Long id, Model model) {
// ...
return "user/detail";
}
}
在这个例子中,RequestMappingHandlerMapping
会将/user/list
映射到list()
方法,将/user/detail/{id}
映射到detail()
方法。
3.2 HandlerMapping 的选择
DispatcherServlet会遍历WebApplicationContext中所有的HandlerMapping,找到第一个能够处理当前请求的HandlerMapping。所以,HandlerMapping的配置顺序很重要。
通常情况下,RequestMappingHandlerMapping
是默认配置的,不需要手动配置。
四、HandlerAdapter:适配器模式的典范
HandlerAdapter的作用是适配Handler,将Handler的调用方式转换为DispatcherServlet可以理解的方式。因为Handler的类型有很多种,比如Controller方法、HttpRequestHandler、Servlet等等,DispatcherServlet不可能直接调用所有的Handler。
SpringMVC提供了多种HandlerAdapter,常用的有:
- RequestMappingHandlerAdapter: 适配
@RequestMapping
注解的Controller方法。 - HttpRequestHandlerAdapter: 适配HttpRequestHandler。
- SimpleControllerHandlerAdapter: 适配Controller接口。
4.1 RequestMappingHandlerAdapter 的使用
RequestMappingHandlerAdapter
主要负责调用带有@RequestMapping
注解的Controller方法。它会处理方法参数的绑定、方法返回值的处理等等。
@Controller
public class MyController {
@RequestMapping("/hello")
public String hello(@RequestParam("name") String name, Model model) {
model.addAttribute("message", "Hello, " + name + "!");
return "hello";
}
}
在这个例子中,RequestMappingHandlerAdapter
会将请求参数name
绑定到hello()
方法的参数name
上,并将返回值"hello"
作为视图名称。
4.2 HandlerAdapter 的选择
DispatcherServlet会遍历WebApplicationContext中所有的HandlerAdapter,找到第一个能够处理当前Handler的HandlerAdapter。所以,HandlerAdapter的配置顺序也很重要。
通常情况下,RequestMappingHandlerAdapter
是默认配置的,不需要手动配置。
五、ViewResolver:视图解析大师
ViewResolver的作用是将视图名称转换为View对象。View对象负责将模型数据渲染到响应中。SpringMVC提供了多种ViewResolver,常用的有:
- InternalResourceViewResolver: 解析JSP视图。
- ThymeleafViewResolver: 解析Thymeleaf视图。
- FreeMarkerViewResolver: 解析FreeMarker视图。
- ContentNegotiatingViewResolver: 根据请求的Accept头选择合适的ViewResolver。
5.1 InternalResourceViewResolver 的使用
InternalResourceViewResolver
是最常用的ViewResolver,它用于解析JSP视图。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
prefix
:视图文件的前缀,比如/WEB-INF/views/
。suffix
:视图文件的后缀,比如.jsp
。
如果Controller方法返回"hello"
,那么InternalResourceViewResolver
会将它解析为/WEB-INF/views/hello.jsp
。
5.2 ThymeleafViewResolver 的使用
如果使用Thymeleaf作为视图引擎,需要配置ThymeleafViewResolver
。
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="cacheable" value="false" />
<property name="characterEncoding" value="UTF-8"/>
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver"/>
<property name="enableSpringELCompiler" value="true"/>
</bean>
<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
5.3 ViewResolver 的选择
DispatcherServlet会遍历WebApplicationContext中所有的ViewResolver,找到第一个能够解析当前视图名称的ViewResolver。所以,ViewResolver的配置顺序也很重要。
通常情况下,InternalResourceViewResolver
或者ThymeleafViewResolver
是默认配置的,需要手动配置。
六、总结
好了,各位看官,咱们今天就聊到这里。SpringMVC的请求处理流程,从DispatcherServlet这位总调度员,到HandlerMapping找到对的人,再到HandlerAdapter进行适配,最后到ViewResolver这位视图解析大师,整个过程就像一条精密的流水线,环环相扣,有条不紊。
希望通过这篇文章,各位能够对SpringMVC的请求处理流程有一个更深入的理解。记住,掌握了这些核心概念,才能更好地驾驭SpringMVC,写出更优雅、更高效的Web应用。
下次再见!