springMVC源码解读笔记

1: DispatcherServlet 的初始化流程(调用的init方法)
a) 初始化spring高级容器,WebApplicationContext(容器初始化12个步骤)
Servlet类的init方法----GenericServlet类的init()---HttpServletBean类的init()--initServletBean()这个方法是FrameworkServlet类实现的---initWebApplicationContext()初始化wbc容器方法--
a.1) this.configureAndRefreshWebApplicationContext(cwac); 配置并刷新容器方法---wac.refresh();----AbstractAoolicationContext类的 refresh()方法, 该方法中有12个步骤,具体看 https://blog.csdn.net/u011151359/article/details/98496427
经过这12个步骤之后, 容器创建完成
a.2) this.onRefresh(wac);---DispatcherServlet类的onRefresh()--this.initStrategies(context);这里是模板方法模式,有一些策略集合方法供子类实现
b) 初始化DispatcherServlet类需要的一些策略集合(比如: 初始化多部件解析器,初始化国际化解析器,初始化主题解析器,初始化处理器映射器,初始化处理器适配器,初始化异常解析器,初始化视图解析器..), 这里只关注 处理器映射器,处理器适配器. 初始化处理器映射器代码中, 先从所有祖宗容器中获取所有的HandlerMapping, 如果获取不到,当前容器中根据"handlerMapping" 来获取HandlerMapping, 并返回完成初始化, 如果这二步都没有获取到处理器映射器(HandlerMapping), 此时有一个兜底代码: 获取默认的处理器映射器(即: 从默认的配置文件:DispatcherServlet.properties 中读取处理器映射器), 同理, 初始化处理器适配器的代码中,先从所有祖宗容器中获取所有handlerAdapter, 没有, 从当前容器中根据"handlerAdapter"获取处理器适配器, 有就返回,如果没有,也是一个兜底的代码, 从默认的DispatcherServlet.properties 中获取处理器适配器
这里有个面试题: springmvc 如果没有在springmvc.xml中配置处理器映射器和处理器适配器,是否可以正常处理请求??
这里需要知道springmvc处理请求的11个步骤,并且没有处理器映射器, 处理器适配器,是不行的, 还要知道springmvc有一个兜底策略,从默认的配置文件中加载默认的处理器适配器, 处理器映射器
2: DispatcherServlet的处理请求的流程(调用的 service方法)
a) 从Servlet类的service方法,---到doGet/doPost方法--到FrameworkServlet类的processRequest()方法--到doService()方法-- 到DispatcherServlet的doService方法--doDispatch()方法
b) DispatcherServlet类的核心方法就是doDispatch()
上面说到DispatcherServlet初始化时候, 会有一个兜底的策略, 从默认配置文件 DispatcherServlet.properties,加载处理器映射器(RequestMappingHandlerMapping),处理器适配器(RequestMappingHandlerAdapter), 接下来看看这二个处理器的初始化方法...
RequestMappingHandlerMapping的初始化方法: 1: 看xml文件中的是否有标签 2: 看该对象是否有实现InitializingBean接口,有的话,afterPropertiesSet() 这个方法就是对象的初始化方法.
而RequestMappingHandlerMapping 是实现了InitializingBean接口, afterPropertiesSet()---initHandlerMethods();---processCandidateBean(beanName);---detectHandlerMethods(beanName);---getMappingForMethod(method, userType);这个方法是将Controller类上的 RequestMapping注解和方法上的注解拼接起来,url. registerHandlerMethod(handler, invocableMethod, mapping);这二个方法是组装了二个map
在该方法中,组装了二个map: mappingLookup(key:RequestMappingInfo , value:handlerMethod) urlLookup(key:url, value:RequestMappingInfo 这里是一个url对应多个映射关系, 这里是基于rest风格的请求, 一个url因为 请求的method(get,post..)不同,从而访问不同的Controller方法)
如图所示:



处理器映射器的目的是能够根据 url找到对应的Controller方法, 这就需要以上二个map来实现精准匹配,, 这里的映射关系映射好了后,接下来就是处理
RequestMappingHandlerMapping的处理流程: 在DispatcherServlet类中doDispatch()方法中, 有mappedHandler = this.getHandler(processedRequest);----mapping.getHandler(request);这个方法返回的是一个处理器执行器调用链HandlerExecutionChain(里面包含一个Handler 和多个interceptors)----之后根据这个Handler找到对应的处理器适配器HandlerAdapter,---ha.handle() 这个方法返回了ModelAndView---this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); 这个方法是处理DispatcherServlet的结果
RequestMappingHandlerAdapter, 可以看到这个类也实现了InitializingBean接口, 所以初始化,直接看 afterPropertiesSet()实现即可 ,

用户向服务器发送请求,请求会到DispatcherServlet,DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI),然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括一个Handler处理器对象、多个HandlerInterceptor拦截器对象),最后以HandlerExecutionChain对象的形式返回。
DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;根据返回的ModelAndView,选择一个适合的ViewResolver返回给DispatcherServlet;ViewResolver 结合Model和View,来渲染视图,最后将渲染结果返回给客户端。
==========================================================================
SpringMVC容器的初始化过程: 首先我们从web.xml中开始, 在web.xml中配置contextLoaderListener, 他的作用是启动web容器时候,自动装配ApplicationContext的配置信息, 因为ContextLoaderListener实现了ServletContextListener接口,所以容器启动的时候,会自动执行ContextInitialized()方法, 这样就能够在客户群请求之前想 ServletContext中添加任意对象,
contextLoaderListener初始化核心逻辑就是,执行ServletContextListener的 contextInitialized()方法 ----contextInitialized(),该方法中判断context是否为null, 为null就创建context容器 ---createWebApplicationContext()---this.determineContextClass(sc)中,先根据传进来的容器servletContext(这里的servletContext, tomcat启动时候回创建ServletContext上下文环境对象,之后读取web.xml,首先读取和这二个标签, 也就是说优先从web.xml中获取配置的"contextClass"对应的全限定类名),获取全限定类名使用反射,创建容器, 如果创建为null, 这里也有一个兜底的代码,从默认的defaultStrategies中获取全限定类名,之后反射创建容器对象. defaultStrategies这个就是默认的配置文件映射成的对象, 在静态代码块中有读取配置文件ContextLoader.properties而来, 也就是不管你赔不配置,最终都会有默认的容器生成
创建了容器之后,有一个配置刷新Web容器的方法--this.configureAndRefreshWebApplicationContext(cwac, servletContext); --这个方法中先是配置容器属性, 之后又个刷新方法--wac.refresh()
关于refresh()的解析
https://blog.csdn.net/u011151359/article/details/98496427
经过这12个步骤之后, 容器创建完成
refresh()中obtainFreshBeanFactory()方法解析: 这个方法是refresh()的核心之一: 该方法中做了二件事: 1, refreshBeanFactory():将xml转换为BeanDefinition,存入BeanFactory中, 创建beanFactory、指定序列化Id、定制beanFactory、加载bean定义
2, getBeanFactory():返回beanFactory实例
总结:
1: DispatcherServlet 前端控制器,作用:接受请求,然后分发请求给对应的处理组件
2: HandlerMapping , 处理器映射器, 作用是将请求,和Controller方法 建立映射关系, 并返回 处理执行调用链对象(一个Handler, 多个HandlerInterceptor)
3: HandlerAdapter , 根据这个Handler获取对应的 处理这个请求的Controller, Controller处理完请求后,返回ModelAndView
4: ViewResolver ,视图解析器, 解析ModelAndView,返回对应的视图给前端
SpringMVC, 先从DispatcherServlet的初始化流程(init), 之后是DispatcherService的处理请求流程(service)
先从DispatcherServlet的初始化流程(init):
DispatcherServlet这个类,
FrameworkServlet, 这个类作用有2个: 1,创建WebApplicationContext容器, 2, 初始化一些策略集合(比如,文件解析器, 初始化多部件解析器,初始化国际化解析器,初始化主题解析器,初始化处理器映射器,初始化处理器适配器,初始化异常解析器,初始化视图解析器..) 初始化策略集合的实现 是在DispatcherServlet中完成的
AbstractApplicationContext: 这个类作用是 配置和刷新容器(12个步骤)
DispatcherService的处理请求流程(service方法):
HttpServlet类: 作用是 处理请求(里面有 doGet() , doPost() )
FrameworkServlet类: 处理请求, doService()
DispatcherServlet类; doDispatch() 找到请求对应的Controller,分发给他处理请求,返回ModelAndView
springMVC源码解读笔记的更多相关文章
- SpringMVC源码解读 - HandlerMapping
SpringMVC在请求到handler处理器的分发这步是通过HandlerMapping模块解决的.handlerMapping 还处理拦截器. 先看看HandlerMapping的继承树吧 可以大 ...
- SpringMVC源码解读 - RequestMapping注解实现解读 - RequestMappingInfo
使用@RequestMapping注解时,配置的信息最后都设置到了RequestMappingInfo中. RequestMappingInfo封装了PatternsRequestCondition, ...
- SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系
一般我们开发时,使用最多的还是@RequestMapping注解方式. @RequestMapping(value = "/", param = "role=guest& ...
- SpringMVC源码解读 - RequestMapping注解实现解读
SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系 https://www.cnblogs.com/leftthen/p/520840 ...
- spring-mvc源码阅读笔记
简要的做一些spring-mvc部分的源码学习笔记 Spring-mvc做的工作主要是俩大方面吧:一个是初始化一个ioc容器,一个是mvc部分的控制和视图模块的实现. 先说下ioc容器的初始化部分:i ...
- js便签笔记(10) - 分享:json2.js源码解读笔记
1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...
- js便签笔记(10) - 分享:json.js源码解读笔记
1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...
- SpringMVC 源码解析笔记
作者笔记仓库:https://github.com/seazean/javanotes 欢迎各位关注我的笔记仓库,clone 仓库到本地后使用 Typora 阅读效果更好. 一.调度函数 请求进入原生 ...
- springMVC 源码解读系列(一)初始化
先看看DispatcherServlet的类机构: 初始化时序图: servlet初始化会调用 init 方法,换句话说就是springMVC进行初始化的时候首先会去执行HttpServletBean ...
随机推荐
- Windows核心编程 第27章 硬件输入模型和局部输入状态
第27章 硬件输入模型和局部输入状态 这章说的是按键和鼠标事件是如何进入系统并发送给适当的窗口过程的.微软设计输入模型的一个主要目标就是为了保证一个线程的动作不要对其他线程的动作产生不好的影响. 27 ...
- Win64 驱动内核编程-24.64位驱动里内嵌汇编
64位驱动里内嵌汇编 讲道理64位驱动是不能直接内链汇编的,遇到这种问题,可以考虑直接把机器码拷贝到内存里,然后直接执行. 获得机器码的方式,可以写好代码之后,直接通过vs看反汇编,然后根据地址在看内 ...
- Android持续优化 - 提高流畅度
http://www.cnblogs.com/purediy/archive/2013/12/26/3492865.html
- HR:“最喜欢阿里出来的程序员了,技术又好又耐艹!” 我:???
面试造火箭,进厂拧螺丝?真的是这样吗? 缘起 估计不少同学都是被标题吸引进来的.事先声明,这句话不是我虚构的,而是我实实在在从同事的口中听到的,而且还不止一次. 当时的场景就是很正常的交谈,别人也并没 ...
- 第一章 FreeBSD之系统安装
一.默认选择 >>[Boot Multi User],按回车键 二.默认选择 >> [Install] 三.选择默认的键盘设置 >>[Select] 四.配置主机名 ...
- Java学习之jackson篇
Java学习之jackson篇 0x00 前言 本篇内容比较简单,简单记录. 0x01 Json 概述 概述:JSON(JavaScript Object Notation, JS 对象简谱) 是一种 ...
- 2020BUAA-团队介绍-采访
团队作业-团队介绍和采访 项目 内容 课程:北航2020软件工程 博客园班级地址 作业要求 团队作业-团队介绍和采访 团队介绍 姓名 有图有真相 个人介绍 刘y 精通(没那么熟悉)c++和python ...
- 重新整理 .net core 实践篇————配置应用[一]
前言 本来想整理到<<重新整理.net core 计1400篇>>里面去,但是后来一想,整理 .net core 实践篇 是偏于实践,故而分开. 因为是重新整理,那么就从配置开 ...
- [bug] Error updating database. Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MyS
sql语句写错了,如图,where前多了个逗号
- 042.Python进程队列介绍
进程队列介绍 1 基本语法及过程 先进先出,后进后出,q = Queue() 过程 (1)把数据放到q队列中 put (2)把书局从队列中拿出来 get from multiprocessing i ...