介绍
上篇文章简单介绍了MVC的含义,本篇文章介绍Spring MVC的一个概貌,同时也是核心内容。
Spring MVC是基于Servlet API来实现的,所以,它就只适用于那些使用Java Servlet技术并且需要部署到Servlet容器的应用。
Spring MVC的正式名称是Spring WebMVC,跟对应的JAR包名字spring-webmvc-5.1.7.RELEASE.jar(我使用的版本是5.1.7)是一致的。Spring框架里面还有另外一个Web框架,是基于响应式的(Reactive),叫做Spring WebFlux,这里暂且不讨论。
Spring MVC也依赖于Spring IoC容器来配置、自动发现MVC的各个组件。
Spring MVC架构、核心
前面文章已经说过,控制器就是起到串联请求处理的各个步骤,包括,请求的输入、转换成业务对象、校验、调用业务逻辑组件、将执行结果交给视图组件进行渲染、填充响应内容等。
在Spring MVC也是如此,它也是围绕这么一个前端控制器来设计的,这个前端控制器就被设计成一个Servlet,就是DispatcherServlet:
这里的设计思想就是DispatcherServlet从Servlet容器接管各个请求,然后串联请求处理的各个步骤,串联的时候采用接口,而各个步骤实际工作是委托给由Spring IoC配置的各个具体组件,如果某个步骤没有配置具体组件,那么会采用默认的配置。
这样的设计很灵活,每个步骤都可以自由配置,甚至开发自己的具体组件。
当然,Spring MVC中的控制器可以说是分层的,最顶层的控制器就是DispatcherServlet,叫做调度器或分派器,它接管的请求配置在Servlet容器中。比如,可以使用部署描述符web.xml中配置一个DispatcherServlet,其名称是appA
,它映射到请求/appA/*
;可以再配置一个DispatcherServlet,其名称是appB
,它映射到请求/appB/*
。
再往下一层的控制器是基于注解@Controller
的控制器组件(这就是前面文章所提到的Spring IoC容器基于注解生成Bean),它也可以配置请求的映射模式。
最低层的控制器在Spring MVC中叫做Handler,它是@Controller
控制器组件中的某个方法,采用@RequestMapping等注解来配置请求的映射模式。即Handler就是Java类中的某个方法。
所以,以后在Spring MVC中这三个层次的控制器就分别叫做DispatcherServlet(调度器/分派器)、Controller(控制器)、Handler(处理器)。
而Spring MVC的视图层就是由上图中的ViewRecolver
以及相应的视图技术组件(JSP、Thymeleaf、FreeMarker)来担当。ViewRecolver
会将Handler返回的逻辑视图名字(就是一个字符串)解析到一个实际的视图(模板),相应的视图技术组件会将执行结果渲染到视图模板。
那模型层呢?模型层实际上就是你所要开发的业务应用代码,这里又可以进一步划分层次,比如服务层、数据访问层等。从上图中可以看到,原来没有Spring MVC的时候,开发人员需要开发的代码包括了现在Spring MVC提供的所有功能,而不仅仅是业务逻辑;而现在,开发人员只需要关注业务逻辑的开发即可。
HandlerMapping
:就是映射请求和Handler的,一个请求来了,首先要找到应该调用的Handler;HandlerAdapter
:是用来帮助DispatcherServlet调用Handler的,实际上是向DispatcherServlet屏蔽调用细节的,比如,有些Handler的调用需要解析注解;HandlerExceptionResolver
:用来解决Handler调用过程中产生的异常;ViewResolver
:上面已经说过;LocaleResolver
和LocaleContextResolver
:解决视图的国际化问题的,比如时区、语言等;ThemeResolver
:解决Web应用的主题,比如每个用户都有自己的个性化的布局;MultipartResolver
:解决multi-part类型的请求,比如文件上传等,但需要第三方的multipart解析库;FlashMapManager
:用来存储、获取和管理FlashMap
实体的,FlashMap又是用来管理Flash attributes,Flash attributes又是为了实现POST/Redirect/GET模式的,这个模式又是为了解决POST/Forward/GET模式导致的多次提交问题。
Spring MVC的请求处理流程
实际上,就是DispatcherServlet
串联的请求处理流程:
- 首先,找到绑定到这个请求的Spring IoC容器(实际上就是
WebApplicationContext
的实例,这篇文章及之前的文章是使用standalone应用作为示例来配置和生成Bean,它们使用的是ApplicationContext
的实例),这样,处理过程中就可以使用这个Spring IoC容器了; - 绑定
LocaleResolver
到这个请求,以便在准备数据、渲染视图的时候可以处理国际化问题; - 绑定
ThemeResolver
到这个请求,以便决定使用哪个主题; - 如果指定了
MultipartResolver
,就要在这个请求中找multiparts,然后把这个请求包装成MultipartHttpServletRequest
; - 然后,就根据某种匹配模式(比如URL、HTTP方法等)寻找匹配的
Handler
,如果找到了,那就执行与之有关的一个执行链(因为可以为Handler
配置preprocessors和postprocessors),从而准备好模型和渲染; - 如果返回了模型,那么就渲染视图,否则就不渲染视图。
实际上,在寻找到匹配的Handler之后,还可能执行从请求中提取数据转换为业务对象的步骤(这个视Handler的参数决定),然后进行Bean校验(也要视配置决定)。
总结
- Spring MVC基于Servlet;
- Spring MVC依赖于Spring IoC,要生成和配置请求处理所需要的各个具体组件Bean;
- Spring MVC的核心是DispatcherServlet 串联 请求处理的各个步骤,各个步骤的执行委托给配置好的Spring IoC容器托管的各个具体组件Bean;
- Spring MVC的核心流程本质上就是DispatcherServlet 串联 请求处理的各个步骤的流程,最核心的步骤就是:
- 寻找匹配的Handler
- 执行Handler
- 将执行结果封装成模型
- 返回模型和视图(具有逻辑视图名)
- 视图解析器解析成实际视图并渲染。
- 这样,应用开发人员职责单一了,只需要开发业务逻辑代码即可,数据的呈现即视图(模板)可以交给前端工程师设计和开发,只要约定好接口和数据模型即可。
- 同时,可以灵活配置各个步骤的具体组件Bean,已有的不满足需要的话,就自己开发一个具体组件。