写点什么

Spring Boot「14」MVC 与前端控制器模式

作者:Samson
  • 2022-10-25
    上海
  • 本文字数:2812 字

    阅读完需:约 9 分钟

Spring Boot「14」MVC 与前端控制器模式

[Spring Boot] Spring MVC and Front Controller

Spring MVC 采用典型的 Front Controller 架构。DispatcherServlet 作为其中的 Front Controller 负责将用户请求匹配到对应的 Controller 中,并将 Controller 返回的数据交给 ViewResolver 根据不同的模板引擎(例如 JSP、Thymeleaf 等)渲染出响应的 View 返回给用户。下图源自于baeldung,详细描述了 Spring MVC 的具体工作流程:



01-基础概念

在学习 Spring MVC 时,与 Servlet 相关地诸多概念让初学者非常的头疼。本节中就对这些基本概念进行一下梳理,帮助各位更好地理解这些概念。

01.1-Servlet

首先,第一个概念就是 Servlet。简单来说,Servlet 就是一个 Java 类,它能够处理请求,并返回一个响应。它的接口定义是:


public interface Servlet {    void init(ServletConfig var1) throws ServletException;    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;    void destroy();        String getServletInfo();    ServletConfig getServletConfig();}
复制代码


init\destroy\service 是 Servlet 整个声明周期中三个比较重要的函数。其中 service 就是其处理 request 并返回 response 的接口。


Spring MVC 中最重要的一个 Servlet 实现就是 DispatcherServlet。

01.2-Servlet 容器

Servlet 运行在 Servlet 容器中,由容器管理。Servlet 容器是 Web 服务器或应用服务器的一部分,为 Servlet 提供运行时上下文,例如网络服务、MIME 解析等;Servlet 容器可以运行在 Web 服务器所在的进程中,也可以是同一主机上的不同进程,甚至可以是不同主机上的进程。当 Web 服务器收到 Request 请求时,会转交给 Servlet 容器。之后,Servlet 容器会选择一个 Servlet 来处理请求,并将响应返回给 Web 服务器。

01.3-ServletContext

ServletContext 定义了 Web 应用程序的 servlet 视图。以下为 Servlet Specification 对 ServletContext 的描述:


The ServletContext interface defines a servlet's view of the Web application within which the servlet is running.


怎么来理解这句话呢?一个 Web 应用中所定义的所有的 Servlet 都是运行在某个 ServletContext 下的。而且,每个 ServletContext 都关联了一个路径,称之为 context path。Servlet 容器会根据请求的 URL 来选择与其匹配的 ServletContext,并将请求交与其处理。


与 context path 相对应的,ServletContext 中的所有 Servlet 也都关联了一个路径,称之为 servlet path。它是相对于 context path 的一个相对路径。举例说明,如果我们的应用关联的 context path 为 /demo,并且有一个 Servlet 且 它的 servlet path 为 /hi。那么,对 URL 为 /demo/hi 的请求将由此 Servlet 处理。


当我们在 Tomcat 中部署 Web 应用时,需要增加配置文件 conf/Catalina/localhost/${web-app-name}.xml,且里面的内容与下面类似:


<Context path="/demo" docBase="demo" > 
复制代码


docBase 指定了我们 Web 应用所在的磁盘位置,path 就是应用对应的 ServletContext 的 context path。


如何定义一个应用的 context path 呢?有如下几种方式:


  1. 以 Property 的方式,在 application.properties 或 application.ymal 中指定:server.servlet.context-path=/demo

  2. 通过环境变量的方式指定

  3. (2.x) export SERVER_SERVLET_CONTEXT_PATH=/demo unix | set SERVER_SERVLET_CONTEXT_PATH=/baeldung windows

  4. (1.x) SERVER_CONTEXT_PATH

  5. 通过编程方式指定:

  6. (2.x) WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>

  7. (1.x) EmbeddedServletContainerCustomizer


如何向 ServletContext 中注册一个 Servlet 呢?


  1. 在 Jakarta EE 中,可以通过:

  2. web.xml 中的<servlet></servlet>标签

  3. @WebServlet注解

  4. 在 Spring Boot 中,可以通过:

  5. web.xml 中的<servlet></servlet>标签

  6. 编程方式指定: WebApplicationInitializer & WebMvcConfigurer | ServletRegistrationBean

  7. 通过 Property 指定:

  8. servlet.name=dispatcherExample & servlet.mapping=/dispatcherExampleURL

  9. System.setProperty("custom.config.location", "classpath:custom.properties"); & System.getProperty("custom.config.location");

  10. spring.mvc.servlet.path=/test

DispatcherServlet

在 Spring MVC 中,DispatcherServlet 是应用的入口,负责将 HttpRequests 定向到 handler。HandlerAdapter 接口主要是为了方便处理 HttpServletRequest。


public interface HandlerAdapter {    boolean supports(Object handler);    @Nullable    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;}
复制代码


supports 用来判断是否支持某个 handler 实例;handle 方法接收 request & response & handler 对象,返回一个 ModelAndView 对象,后续会被 DispatcherServlet 处理。调用 DispatcherServlet#getHandler 时,每个实现了 HandlerAdapter 接口的对象会被放置到 HandlerExecutionChain 中,随着处理过程的推进,它们的 handle() 方法会被应用到 HttpServletRequest 上。


常用的 HandlerAdapter 实现:


  • SimpleControllerHandlerAdapter & BeanNameUrlHandlerMapping,负责将 request 定向到实现了 Controller 接口的实例中。同样是 Spring MVC 中默认的 HandlerAdapter。

  • SimpleServletHandlerAdapter,负责将 DispatcherServlet 收到的 request 定向到其他实现了 Servlet 接口的实例,调用其 service() 方法。

  • (deprecated in Spring 3.2)AnnotationMethodHandlerAdapter & DefaultAnnotationHandlerMapping,负责将 request 定向到标注了@RequestMapping注解的实例中。

  • RequestMappingHandlerAdapter & RequestMappingHandlerMapping,将 request 定向到@RequestMapping注解的方法。@EnableWebMvc<mvc:annotation-driven />会自动向容器中注入这两个 bean。

  • HttpRequestHandlerAdapter,负责处理 HttpRequests,将 request 定向到实现了 HttpRequestHandler 接口的实例中,调用其 handleRequest() 方法,返回值为 void 而非 ModelAndView。一般用在不需要渲染视图的场景。


除上述部分外,Spring MVC 中还包括如下组件:


  • DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE 关联到一个 WebApplicationContext

  • DispatcherServlet 通过 getHandler 方法获得所有实现了 HandlerAdapter 接口的对象,HandlerAdapter 需要与 HandlerMapping 一起使用。

  • (可选)ViewResolver,主要通能:决定提供何种类型的视图,以及从哪里获取对应的视图。

  • (可选)LocaleResolver,主要功能:customize session, request, or cookie information

  • (可选)ThemeResolver,主要功能:视图主题相关

  • (可选)MultipartResolver,主要功能:将 request 包装成为 MultipartHttpServletRequest

  • HandlerExceptionResolver,主要功能:Spring 3.2 之前统一异常处理方式

发布于: 刚刚阅读数: 3
用户头像

Samson

关注

还未添加个人签名 2019-07-22 加入

InfoQ签约作者 | 阿里云社区签约作者

评论

发布
暂无评论
Spring Boot「14」MVC 与前端控制器模式_Java_Samson_InfoQ写作社区