SpringMVC 请求处理流程详解:从 DispatcherServlet 到 ViewResolver

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 接收到请求后,会按照以下步骤进行处理:

  1. 查找HandlerMapping: DispatcherServlet会遍历WebApplicationContext中所有的HandlerMapping,找到能够处理当前请求的HandlerMapping。HandlerMapping的作用是根据请求的URL,找到对应的Handler(通常是一个Controller方法)。
  2. 获取HandlerExecutionChain: HandlerMapping找到Handler后,会返回一个HandlerExecutionChain,它包含了Handler和一些拦截器(Interceptor)。
  3. 查找HandlerAdapter: DispatcherServlet会遍历WebApplicationContext中所有的HandlerAdapter,找到能够处理当前Handler的HandlerAdapter。HandlerAdapter的作用是适配Handler,将Handler的调用方式转换为DispatcherServlet可以理解的方式。
  4. 执行Handler: HandlerAdapter会调用Handler,执行具体的业务逻辑。Handler执行完毕后,会返回一个ModelAndView对象,它包含了视图名称和模型数据。
  5. 处理异常: 如果在请求处理过程中发生异常,DispatcherServlet会查找WebApplicationContext中所有的HandlerExceptionResolver,找到能够处理当前异常的HandlerExceptionResolver。HandlerExceptionResolver的作用是将异常转换为ModelAndView对象。
  6. 查找ViewResolver: DispatcherServlet会遍历WebApplicationContext中所有的ViewResolver,找到能够解析当前视图名称的ViewResolver。ViewResolver的作用是将视图名称转换为View对象。
  7. 渲染视图: 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应用。

下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注