MVC

作为一个MVC框架,必须回答一下几个问题

  • 请求映射到控制器
  • 请求数据进行绑定
  • 视图渲染

而spring mvc是如何解决这几个问题的呢?

首先,从DispatcherServlet这个入口开始分析,DispatcherServlet继承于FrameworkServlet,而FrameworkServlet继承HttpServletBean,HttpServletBean又继承与HttpServlet,先从
HttpServletBean的init方法开始分析

@Override
public final void init() throws ServletException {//省略// Let subclasses do whatever initialization they like. initServletBean();//这是个空方法,可以给其子类进行重写}

再从其子类FrameworkServlet重写的initServletBean()方法

@Override
protected final void initServletBean() throws ServletException {//日志块省略try {//初始化springMvc的ApplicationContext、并查找是否有spring的ApplicationContext 并将其设置为root applicationContext ,初始化spring mvc的beanthis.webApplicationContext = initWebApplicationContext();//空方法,可扩展initFrameworkServlet();}//catch块,日志省略
}

继续分析DispatcherServlet init()方法

protected void initStrategies(ApplicationContext context) {//初始化处理mine为multipart/form-data的处理器initMultipartResolver(context);//初始化本地化处理器,默认是以用户的http请求的AcceptHeaderLocaleResolverinitLocaleResolver(context);//初始化主题处理器initThemeResolver(context);//初始化HandlerMappingsinitHandlerMappings(context);//初始化处理器适配器initHandlerAdapters(context);//处理异常处理器initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);//处理视图转换initViewResolvers(context);initFlashMapManager(context);
}

从上面代码可以看出来,DispatcherServlet会初始化一些处理器,再分析其处理请求的方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {//判断是否是multipart/form-dataprocessedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 将请求映射到具体的处理器mappedHandler = getHandler(processedRequest);if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}对处理器进行适配HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (logger.isDebugEnabled()) {logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}拦截器处理if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 调用具体的控制器进行处理mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);拦截器处理mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}//处理异常、渲染视图processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}//省略
}

上述代码包括了请求到响应 spring做的过程。我们来细化分析一下。

首先我们来分析请求映射到逻辑处理器的过程

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {for (HandlerMapping hm : this.handlerMappings) {if (logger.isTraceEnabled()) {logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");}HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;
}

从这段代码看,其会遍历所有的HandlerMapping,然后获取一个HandlerExecutionChain执行对象,而入参是HttpServletRequest,意味着这个HandlerMapping可以根据http请求的所有信息获取到一个控制器。这是第一个扩展点,我们可以实现一个HandlerMapping来处理请求映射。再看HandlerExecutionChain这个类

public class HandlerExecutionChain {private final Object handler;private HandlerInterceptor[] interceptors;}

这个类最重要的两个属性,可以看出其对执行对象里面包含了两个部分,一个是控制器,另一个则是拦截器数组,这是第二个扩展点,我们可以实现HandlerInterceptor,在控制器处理前后进行一些操作。

我们来这个操作,其会获取一个控制器的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {for (HandlerAdapter ha : this.handlerAdapters) {if (logger.isTraceEnabled()) {logger.trace("Testing handler adapter [" + ha + "]");}if (ha.supports(handler)) {return ha;}}
}

从这个方法的执行,我们可以看出来其依旧是遍历handlerAdapters后返回第一个HandlerAdapter进行处理Handler,所以我们可以实现HandlerAdapter这个接口,自定义对Handler进行处理,这是第三个扩展点

继续玩下走,在processDispatchResult()方法中,先判断是否有exception,若有且不是ModelAndViewDefiningException,则交给HandlerExceptionResolver处理,HandlerExceptionResolver是个接口,可以看出这是第四个扩展点。继续往下走,到render()方法,

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine locale for request and apply it to the response.Locale locale = this.localeResolver.resolveLocale(request);response.setLocale(locale);View view;// 判断View是不是字符串if (mv.isReference()) {//交给ViewResolvers处理,将其转换成View对象view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);if (view == null) {throw new ServletException("Could not resolve view with name '" + mv.getViewName() +"' in servlet with name '" + getServletName() + "'");}}else {// No need to lookup: the ModelAndView object contains the actual View object.view = mv.getView();if (view == null) {throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +"View object in servlet with name '" + getServletName() + "'");}}// Delegate to the View object for rendering.if (logger.isDebugEnabled()) {logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");}//将数据渲染到视图中try {view.render(mv.getModelInternal(), request, response);}
}

至此springMVC从请求到响应的流程结束,可以看出springMVC玩的是开闭原则,对修改关闭,可扩展。这是个大体流程,下一篇文章将分析其细节化

转载于:https://www.cnblogs.com/myzhong2014/p/5301847.html

springMVC分析-1相关推荐

  1. springMVC分析-2

    springMVC的请求映射 上一次分析了一下springMVC的大致流程,这次细分一下,对请求映射进行分析. 先从DispatcherServlet中的getHandler()方法分析 protec ...

  2. spring和springMVC配置文件中的扫描包如何配置

    我的项目大概文件路径: 然后进入主题: spring的配置文件名称为applicationContext.xml springMVC的配置文件名称为dispatcherServlet-servlet. ...

  3. SSM框架学习文档以及SSM整合(附Github地址=含SSM学习时的实例代码)

    SSM框架学习 软件架构: 基于流行SSM框架:Spring+SpringMVC+Mybatis 项目配置: 使用Maven进行项目jar导入 ​ 使用Git进行版本控制,并将每次编写的代码上传到Gi ...

  4. spring注解驱动开发-10 Servlet3.0

    Spring AOP实现 前言 servlet3.0简介 ServletContainerInitializer shared libraries(共享库) / runtimes pluggabili ...

  5. 尚硅谷Spring注解开发学习笔记

    文章目录 前言 1.课程安排 1.1.容器 1.2.扩展原理 1.3.Web 2.配置文件开发 2.1.导入Spring-context依赖包 2.2.编写Spring配置文件 2.3.编写Perso ...

  6. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  7. SpringMVC启动分析

    以下分析基于JDK1.8 启动的第一步是执行监听器,这里web.xml中配置了一个监听器org.springframework.web.context.ContextLoaderListener 接下 ...

  8. SpringMVC学习(一)———— springmvc框架原理分析和简单入门程序

    一.什么是springmvc? 我们知道三层架构的思想,并且如果你知道ssh的话,就会更加透彻的理解这个思想,struts2在web层,spring在中间控制,hibernate在dao层与数据库打交 ...

  9. SpringMVC之源码分析--ViewResolver(四)

    概述 本章继续学习ViewResolver另一个实现类ContentNegotiatingViewResolver解析器,该类的主要作用是根据同一请求的某些策略,选择对应的View进行渲染.可以把Co ...

最新文章

  1. 看似简单但容易忽视的编程常识
  2. PHP06 PHP操作MySQL
  3. django升级问题
  4. 后台服务系统之搭建ZooKeeper注册中心
  5. 线程打印_线程知识回顾
  6. WebService开发中SoapException的用法
  7. linux之SQL语句简明教程---SUBSTRING
  8. 95-30-010-Channel-AbstractChannel
  9. 促销海报灵感素材,不卖出去都难
  10. android 如何快速检测到画面变化_电瓶修复—如何快速检测电池的好坏2
  11. android SDK安装以及环境变量配置(windows)
  12. JSP中文乱码问题终极解决方案(下)
  13. python import 搜索包路径的机制,以及添加自定义python包的方法
  14. 一篇文章带你搞定 create connection SQLException, url: jdbc:mysql://10.15.16.63:3306/restful, errorCode 1130
  15. 如何升级php到最新版本_如何将PHP升级到最新版本
  16. odi12配置mysql_Oracle数据库之Oracle ODI 12c之多表联合查询以及定时任务设置
  17. java、.net、IOS、Android自学编程学习视频与资料
  18. 如何与新同事共同成长?
  19. ESMTP协议与SMTP协议
  20. 【C++】关于char * tempbuffer = new char[100];

热门文章

  1. 疯狂连连看之开发游戏界面组件一
  2. Aptana 开发环境执行时默认的工作路径
  3. win目录挂载到linux目录遇到的小问题
  4. ROS学习笔记基础2(基础知识和ROS架构)
  5. udp文件服务器,UDP客户端服务器文件传输
  6. visual studio 2017 连接 SQL Server
  7. Python中文本文件的读取(包含指针移动)
  8. 朱啸虎:自己来说可以把一小部分资产购买比特币,作为资产配置是可以考虑的
  9. 新加坡区块链公司Tribe Accelerator完成7000万美元融资
  10. 今日恐慌与贪婪指数为70 贪婪程度有所缓解