• 欢迎访问web前端中文站,JavaScript,CSS3,HTML5,web前端demo
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏web前端中文站吧

spring mvc原理,设计架构,架构图和解决的实际问题

JAVA web前端中文站 2年前 (2017-07-10) 1572次浏览 已收录 0个评论

面试中经常会被问到 Spring MVC 和其他 MVC 框架的区别,以及 Spring Mvc 的原理。本文将通过 Spring MVC 框架的原理,执行流程,解决的实际问题等方面出发,讲明 Spring MVC。

更多精彩内容请看 web 前端中文站
http://www.lisa33xiaoq.net 可按 Ctrl + D 进行收藏

spring mvc 原理,设计架构,架构图和解决的实际问题

Spring Web MVC 是什么

Spring Web MVC 是一种基于 Java 的实现了 Web MVC 设计模式的请求驱动类型的轻量级 Web 框架,即使用了 MVC 架构模式的思想,将 web 层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC 也是要简化我们日常 Web 开发的。
 
另外还有一种基于组件的、事件驱动的 Web 框架在此就不介绍了,如 Tapestry、JSF 等。
 
Spring Web MVC 也是服务到工作者模式的实现,但进行可优化。前端控制器是 DispatcherServlet;应用控制器其实拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resolver)进行视图管理;页面控制器/动作/处理器为 Controller 接口(仅包含 ModelAndView handleRequest(request, response) 方法)的实现(也可以是任何的 POJO 类);支持本地化(Locale)解析、主题(Theme)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持。

Spring Web MVC 能帮我们做什么

  • 让我们能非常简单的设计出干净的 Web 层和薄薄的 Web 层;
  • 进行更简洁的 Web 层的开发;
  • 天生与 Spring 框架集成(如 IoC 容器、AOP 等);
  • 提供强大的约定大于配置的契约式编程支持;
  • 能简单的进行 Web 层的单元测试;
  • 支持灵活的 URL 到页面控制器的映射;
  • 非常容易与其他视图技术集成,如 Velocity、FreeMarker 等等,因为模型数据不放在特定的 API 里,而是放在一个 Model 里(Map 数据结构实现,因此很容易被其他框架使用);
  • 非常灵活的数据验证、格式化和数据绑定机制,能使用任何对象进行数据绑定,不必实现特定框架的 API;
  • 提供一套强大的 JSP 标签库,简化 JSP 开发;
  • 支持灵活的本地化、主题等解析;
  • 更加简单的异常处理;
  • 对静态资源的支持;
  • 支持 Restful 风格。

Spring Web MVC 架构

Spring Web MVC 框架也是一个基于请求驱动的 Web 框架,并且也使用了前端控制器模式来进行设计,再根据请求映射规则分发给相应的页面控制器(动作/处理器)进行处理。

Spring Web MVC 处理请求的流程

spring mvc 原理,设计架构,架构图和解决的实际问题

具体执行步骤如下:

  1. 首先用户发送请求————>前端控制器,前端控制器根据请求信息(如 URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分;图 2-1 中的 1、2 步骤;
  2. 页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在 Spring Web MVC 中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个 ModelAndView(模型数据和逻辑视图名);图 2-1 中的 3、4、5 步骤;
  3. 前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;图 2-1 中的步骤 6、7;
  4. 前端控制器再次收回控制权,将响应返回给用户,图 2-1 中的步骤 8;至此整个结束。

问题:

  1. 请求如何给前端控制器?
  2. 前端控制器如何根据请求信息选择页面控制器进行功能处理?
  3. 如何支持多种页面控制器呢?
  4. 如何页面控制器如何使用业务对象?
  5. 页面控制器如何返回模型数据?
  6. 前端控制器如何根据页面控制器返回的逻辑视图名选择具体的视图进行渲染?
  7. 不同的视图技术如何使用相应的模型数据?

Spring Web MVC 架构

spring mvc 原理,设计架构,架构图和解决的实际问题

架构图对应的 DispatcherServlet 核心代码如下:

 //前端控制器分派方法   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {    HttpServletRequest processedRequest = request;    HandlerExecutionChain mappedHandler = null;    int interceptorIndex = -1;    try {     ModelAndView mv;     boolean errorView = false;     try {      //检查是否是请求是否是 multipart(如文件上传),如果是将通过 MultipartResolver 解析      processedRequest = checkMultipart(request);      //步骤 2、请求到处理器(页面控制器)的映射,通过 HandlerMapping 进行映射      mappedHandler = getHandler(processedRequest, false);      if (mappedHandler == null || mappedHandler.getHandler() == null) {       noHandlerFound(processedRequest, response);       return;      }      //步骤 3、处理器适配,即将我们的处理器包装成相应的适配器(从而支持多种类型的处理器)      HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());      // 304 Not Modified 缓存支持      //此处省略具体代码      // 执行处理器相关的拦截器的预处理(HandlerInterceptor.preHandle)      //此处省略具体代码      // 步骤 4、由适配器执行处理器(调用处理器相应功能处理方法)      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());      // Do we need view name translation?      if (mv != null && !mv.hasView()) {       mv.setViewName(getDefaultViewName(request));      }      // 执行处理器相关的拦截器的后处理(HandlerInterceptor.postHandle)      //此处省略具体代码     }catch (ModelAndViewDefiningException ex) {      logger.debug("ModelAndViewDefiningException encountered", ex);      mv = ex.getModelAndView();     }catch (Exception ex) {      Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);      mv = processHandlerException(processedRequest, response, handler, ex);      errorView = (mv != null);     }     //步骤 5 步骤 6、解析视图并进行视图的渲染     //步骤 5 由 ViewResolver 解析 View(viewResolver.resolveViewName(viewName, locale))     //步骤 6 视图在渲染时会把 Model 传入(view.render(mv.getModelInternal(), request, response);)     if (mv != null && !mv.wasCleared()) {      render(mv, processedRequest, response);      if (errorView) {       WebUtils.clearErrorRequestAttributes(request);      }     }else {      if (logger.isDebugEnabled()) {       logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +         "': assuming HandlerAdapter completed request handling");      }     }     // 执行处理器相关的拦截器的完成后处理(HandlerInterceptor.afterCompletion)     //此处省略具体代码    catch (Exception ex) {      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);     throw ex;    }catch (Error err) {     ServletException ex = new NestedServletException("Handler processing failed", err);     triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);     throw ex;    }finally {     if (processedRequest != request) {      cleanupMultipart(processedRequest);     }    }   }  

核心架构的具体流程步骤如下:

  1. 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet——>HandlerMapping, HandlerMapping 将会把请求映射为 HandlerExecutionChain 对象(包含一个 Handler 处理器(页面控制器)对象、多个 HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
  3. DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
  4. HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个 ModelAndView 对象(包含模型数据、逻辑视图名);
  5. ModelAndView 的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的 View,通过这种策略模式,很容易更换其他视图技术;
  6. View——>渲染,View 会根据传进来的 Model 模型数据进行渲染,此处的 Model 实际是一个 Map 数据结构,因此很容易支持其他视图技术;
  7. 返回控制权给 DispatcherServlet,由 DispatcherServlet 返回响应给用户,到此一个流程结束。

此处我们只是讲了核心流程,没有考虑拦截器、本地解析、文件上传解析等,后边再细述。
到此,再来看我们前边提出的问题:

  1. 请求如何给前端控制器?这个应该在 web.xml 中进行部署描述,在 HelloWorld 中详细讲解。
  2. 前端控制器如何根据请求信息选择页面控制器进行功能处理? 我们需要配置 HandlerMapping 进行映射
  3. 如何支持多种页面控制器呢?配置 HandlerAdapter 从而支持多种类型的页面控制器
  4. 如何页面控制器如何使用业务对象?可以预料到,肯定利用 Spring IoC 容器的依赖注入功能
  5. 页面控制器如何返回模型数据?使用 ModelAndView 返回
  6. 前端控制器如何根据页面控制器返回的逻辑视图名选择具体的视图进行渲染? 使用 ViewResolver 进行解析
  7. 不同的视图技术如何使用相应的模型数据? 因为 Model 是一个 Map 数据结构,很容易支持其他视图技术

在此我们可以看出具体的核心开发步骤:

  1. DispatcherServlet 在 web.xml 中的部署描述,从而拦截请求到 Spring Web MVC
  2. HandlerMapping 的配置,从而将请求映射到处理器
  3. HandlerAdapter 的配置,从而支持多种类型的处理器
  4. ViewResolver 的配置,从而将逻辑视图名解析为具体视图技术
  5. 处理器(页面控制器)的配置,从而进行功能处理

Spring Web MVC 优势

  1. 清晰的角色划分:前端控制器(DispatcherServlet)、请求到处理器映射(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)、处理器或页面控制器(Controller)、验证器(   Validator)、
  2. 命令对象(Command  请求参数绑定到的对象就叫命令对象)、表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
  3. 分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要;
  4. 由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象;
  5. 和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的;
  6. 可适配,通过 HandlerAdapter 可以支持任意的类作为处理器;
  7. 可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制;
  8. 功能强大的数据验证、格式化、绑定机制;
  9. 利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试;
  10. 本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
  11. 强大的 JSP 标签库,使 JSP 编写更容易。

还有比如 RESTful 风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。
 
到此我们已经简单的了解了 Spring Web MVC,下一章我们将通过实例来具体使用下这个框架。

【注:本文源自网络文章资源,由站长整理发布】


web 前端中文站 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:spring mvc 原理,设计架构,架构图和解决的实际问题
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址