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 ...
 
随机推荐
- POJ2337 欧拉路径字典序输出
			
题意: 给一些单词,问是否可以每个单词只用一次,然后连接在一起(不一定要成环,能连接在一起就行). 思路: 这个题目的入手点比较好想,其实就是问欧拉路径,先说下解题步骤,然后在 ...
 - POJ1548最小路径覆盖
			
题意: 给你一个DAG,然后问你最少多少条路径能覆盖所有需要覆盖的点. 思路: 最小路径覆盖,太明显了,每个点向它右下方的点连边,然后...没啥难的地方,不说了. #inclu ...
 - Windows核心编程笔记之进程
			
改变进程基址,获取进程基址 #include <Windows.h> #include <iostream> #include <strsafe.h> #inclu ...
 - [LeetCode]丑数 II&C++中priority_queue和unordered_set的使用
			
[LeetCode]丑数 II&C++中priority_queue和unordered_set的使用 考虑到现实因素,LeetCode每日一题不再每天都写题解了(甚至有可能掉题目?--)但对 ...
 - 安装mysql警告: Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY
			
CentOS安装rpm安装MySQL时爆出警告: warning: mysql-community-server-5.7.18-1.el6.x86_64.rpm: Header V3 DSA/SHA1 ...
 - 解决 Ubuntu 无法使用 root 用户进行 ssh 远程登陆
			
解决 Ubuntu 无法使用 root 用户进行 ssh 远程登陆 操作系统 Ubuntu 20.04.2 LTS 一.修改sshd配置文件 //打开 /etc/ssh/sshd_config 配置文 ...
 - Pulsar 下一代消息平台
			
引言 提起成熟的消息队列或消息引擎,毋庸置疑,大多数人的第一反应一定是 Kafka. Kafka 能够彻底满足海量数据场景下高吞吐.高并发需求,在短短几年内,已经被阿里.腾讯.百度.字节跳动.Netf ...
 - shell初学之nginx(域名)
			
创建两个以域名区分的虚拟网站: 1 #!/bin/bash 2 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/ ...
 - 进程-信号相关 函数-(转自wblyuyang)
			
Linux 中的进程: 程序时一个预定义的指令序列,用来完成一个特定的任务. C 编译器可以把每个源文件翻译成一个目标文件,链接器将所有的目标文件与一些必要的库链接在一起,产生一个可执行文件.当程序被 ...
 - C语言的指针数组与指针数组
			
一.指针数组与指针数组 1,指针数组 顾名思义,即一个元素全部是指针的数组,其形式与普通数组相似,形式如 *a[N]. 在理解指针数组的使用方式前,我先来说下我个人对数组的理解. 比如一维整形数组(形 ...