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 ...
随机推荐
- Python中的socket网络模块
目录 Socket 服务端(server.py) 客户端(client.py) socket中的一些常用方法 Socket 对象(内建)方法 Python Internet 模块 Python3 提供 ...
- UVA11427玩纸牌(全概率+递推)
题意: 一个人玩纸牌游戏,他每天最多玩n局,枚举获胜的概率是a/b,每天玩牌只要获胜概率达到p,那么他今天就不玩了,明天接着玩,如果有一天他的概率没有达到p,(没有达到p的话他今天一定是玩 ...
- [CTF]unicode编码
[CTF]unicode编码 --------------------- 作者:adversity` 来源:CSDN 原文:https://blog.csdn.net/qq_40836553/a ...
- word打印华文字体出现乱码
乱码原因:打印机自带字体库支持的问题 解决方法:解决方法是修改打印机的设置,不使用打印机的字体,直接使用电脑的字体. 具体操作:控制面板-设备和打印机-选中要设置的打印机-打印首选项-图像品质-设置字 ...
- .NET平台系列5 .NET Core 简介
系列目录 [已更新最新开发文章,点击查看详细] 自1995年互联网战略日以来最雄心勃勃的事业 -- 微软.NET战略, 2000年6月30日. 微软公司于2002年2月13日正式推出第一代.N ...
- 【开源技术分享】无需流媒体服务,让浏览器直接播放rtsp/rtmp的神器:EasyMedia
不同于市面上其他需要各种转发到流媒体服务的中间件来说,EasyMedia不需要依赖任何nginx-rtmp,srs,zlmediakit等等第三方流媒体服务,只需要你有rtsp或者rtmp等等协议的视 ...
- 【敏杰开发】Beta阶段事后分析
[敏杰开发]Beta阶段事后分析 设想和目标 Q 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们达到目标了么(原计划的功能做到了几个? 按照原计划交付时间交付 ...
- CF1487 Cat Cycle
一个规律题目要多做多积累 , 脑子不太灵活 CF1487 Cat Cycle 题目大意: 两只猫A,B, A猫从n -> n-1 -> n-2 ... -> 1 -> 2 .. ...
- [c++] 基本概念
内存 栈区和堆区的管理模式有所不同:栈区内存由系统分配和释放,不受程序员控制:堆区内存完全由程序员掌控,想分配多少就分配多少,想什么时候释放就什么时候释放,非常灵活. 栈(Stack)可以存放函数参数 ...
- [Python] execl读写
相关库 读:xlrd 写:xlwt 案例 要求: 将图1中的数据导以图2的形式写入另一个文件中 第一列索引关系:{1:K1-B1,2:K1-B2} ...(18列) 思路: 按行读取数据,根据索引关系 ...