SpringMVC的工作原理(创建篇)
概述
目前 Spring、Springboot 、 Springmvc 算是传统互联网非常常见的技术,Springmvc 重要性向来不如前两个,但是也不影响我们应该更完善的了解Springmvc到底是什么。毕竟一个传统的马工,调试接口天经地义,我们都听过面试造航母,工作拧螺丝。接口就是我们平常工作最锃光瓦亮的那一颗螺丝,如果能理解Springmvc,相信你的工作完成起来能更加快速高效 ,这样就能腾出更多的时间学别的~
实现
在Spring的具体实现上,子容器和父容器都是通过ServletContext的setAttribute方法放到ServletContext中的。在以往依靠tomcat的监听器和Servlet去启动的条件下,ContextLoaderListener会先于DispatcherServlet创建ApplicationContext,DispatcherServlet在创建ApplicationContext时会先找到由ContextLoaderListener所创建的ApplicationContext,再将后者的ApplicationContext作为参数传给DispatcherServlet的ApplicationContext的setParent()方法。也就是说,子容器的创建依赖于父容器的创建,父容器先于子容器创建。在Spring源代码中,你可以在FrameworkServlet中找到如下代码:
wac.setParent(parent);
但是在Springboot将tomcat作为嵌入式容器之后,有了一些改变,先看一下DispatcherServlet是什么时候创建的
小知识:springboot中,DispatcherServlet是什么时候创建的?
从refresh()开始(重要的启动入口),执行到this.onRefresh()然后如下:
tomcatServletWebServerFactory在创建过程中,触发ErrorPageRegistrarBeanPostProcessor后置处理器,创建errorPageCustomizer 在解决属性注入时创建了errorPageCustomizer 解决依赖DispatcherServletPath,创建了其实现类 dispatcherServletRegistration,为了解决依赖创建了DispatcherServlet ;
SpringBoot使用tomcat作为嵌入式servlet容器,在onRefresh()这里完成了嵌入式Servlet容器的创建
我们只关注DispatcherServlet的创建时间点,是在refresh()中的this.onRefresh()创建的就够了,看过源码都知道如下代码完成了Spring IOC容器的创建,那么在此之前 tomcat已经先于执行了。
this.finishBeanFactoryInitialization(beanFactory);
在执行完成上述以后,容器已经创建完成。
DispatcherServlet属性赋值
我们回头看一眼重要的属性赋值,在DispatcherServlet创建过程中,FrameworkServlet的重要属性也赋值完成,如下:
ApplicationContextAwareProcessor去创建,是使用ApplicationContextAware,这里不详细解释,可以看看之前我写的这篇内容(其实写这一篇只是心血来潮)
ApplicationContextAware底层原理详解
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
通过这种方式就Spring ioc容器注入到了FrameworkServlet的WebApplicationContext属性中了,对于之后的调用,我们就能理解为什么父容器和子容器其实是一个容器的事实。
WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;if (this.webApplicationContext != null) {// A context instance was injected at construction time -> use itwac = this.webApplicationContext;
其中,wac即为由DisptcherServlet的父类FrameworkServlet的属性的webApplicationContext,而parent则为由ContextLoaderListener创建的ApplicationContext(这里只是便于理解,其实已经不会执行到setParent()的内容了)。
此后,框架又会调用ServletContext的setAttribute()方法将wac加入到ServletContext中的属性中
在FrameworkServlet中,上图就是作为类中属性存在的容器,WebApplicationContext是ApplicationContext的子接口;
父容器是以org.springframework.web.context.WebApplicationContext.ROOT 作为ServletContext(web应用上下文)的key保存容器。
子容器是以org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcherServlet作为key保存容器
扩展
下图 rootContext是 父容器的容器,下面的DefaultListableBeanFactory类可能好多人都见到过,这里主要是帮助理解,在rootContext的内容如下
说到DefaultListableBeanFactory, 简单介绍一下DefaultSingletonBeanRegistry ,它们是继承的关系,DefaultListableBeanFactory是子类,DefaultSingletonBeanRegistry是父类。这里DefaultSingletonBeanRegistry有几个特别重要的属性
几个属性从上到下依次为一级缓存,三级缓存和二级缓存。听说过三级缓存解决循环依赖吗,指的就是这里的三级缓存。不过多解释,一级缓存是存放已经初始化和实例化好的对象,二级缓存是存放只是实例化好但并没有初始化完成的对象,而三级缓存,放的根本不是对象,而是供循环依赖时调用产生对象的ObjectFactory。这里主要是为了方便理解 singletonObjects是一级缓存;
注: 我们平时getBean取得的对象就是来自于一级缓存
父子容器
介绍这些主要是为了引出 父子容器的关系:
- 首先直观的去比较一级缓存中的数据,这里是Spring容器真实创建好的bean
2. 比较wac和rootContext的对象引用
得出结论:wac和rootContext是同一个对象,都是Spring创建好的ioc容器
至此,我们知道在Springboot中,我们的子容器和父容器是同一个容器!也大概了解了容器和Servlet容器的关系;
注
ServletContext的作用范围是整个应用
创建过程
先看实际继承关系
我们知道 Servlet 的生命周期包括
初始化阶段 ,调用init()方法
响应客户请求阶段,调用service()方法
终止阶段,调用destroy()方法
Springboot默认是在第一次调用时才触发的init初始化,此时DispatcherServlet虽然已经是bean了,但是还没有成为一个可以被使用的bean;
调用过程如下:
org.springframework.web.servlet.HttpServletBean#init
org.springframework.web.servlet.FrameworkServlet#initServletBean
org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
cwac.setParent(rootContext);
...if (!this.refreshEventReceived) {this.onRefresh(wac);}
org.springframework.web.servlet.DispatcherServlet#onRefresh
org.springframework.web.servlet.DispatcherServlet#initStrategies
调用到这里 所以在Servlet初始化时,创建9大DispatcherServlet对象
initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);
在这完成以后,可能大家就都特别熟悉doDispatch()方法了
结论
至此 从run开始到目前为止,已经创建出了一个可以正常使用的DispatcherServlet,其实这部分内容可能没多少人愿意了解,但是它是你理解整个springmvc运行的非常重要的步骤,尤其是对于父子容器、ioc容器、web上下文等的概念。
我们可以通过API直接请求我们的服务了。这里只讲了创建的流程,并没有讲解请求是如何调用的。如果有机会出下一篇,希望能把Springmvc的调用过程讲清楚。
❤❤❤
SpringMVC的工作原理(创建篇)相关推荐
- 【转载】SpringMVC的工作原理
声明: 转载文章署名及贴出原文链接 -------------------------------------------- 知乎-杀戮苍生 原文地址:https://zhuanlan.zhihu.c ...
- SSM三大框架+SpringMVC的工作原理及其流程
SSM三大框架+SpringMVC的工作原理及其流程 一.SSM中各层作用及关系 1.持久层:DAO层(mapper层)(属于mybatis模块) DAO层(Mapper层):主要负责与数据库 ...
- springMVC 的工作原理和机制
转载自 https://www.cnblogs.com/zbf1214/p/5265117.html 工作原理 上面的是springMVC的工作原理图: 1.客户端发出一个http请求给web服务器, ...
- 以太坊的工作原理 程序篇
这篇文章主要讲解以太坊的基本原理,对技术感兴趣的朋友可以看看. 原文地址:How does Ethereum work, anyway? 简介 不管你们知不知道以太坊(Ethereum blockch ...
- 调试器工作原理——基础篇
#include <stdio.h>int main(){printf("Hello, world!n");return 0;} 本文是一系列探究调试器工作原理的文章的 ...
- python调试器原理_调试器工作原理——基础篇
本文是一系列探究调试器工作原理的文章的第一篇.我还不确定这个系列需要包括多少篇文章以及它们所涵盖的主题,但我打算从基础知识开始说起. 关于本文 我打算在这篇文章中介绍关于Linux下的调试器实现的主要 ...
- Linux调试器工作原理——基础篇
英文原文:Eli Bendersky编译:伯乐在线-陈舸 本文是一系列探究调试器工作原理的文章的第一篇.我还不确定这个系列需要包括多少篇文章以及它们所涵盖的主题,但我打算从基础知识开始说起. 关于本文 ...
- 面试官问你 SpringMVC 的工作原理,你还不知道吗?
SpringMVC的工作原理图: SpringMVC流程 1. 用户发送请求至前端控制器DispatcherServlet. 2. DispatcherServlet收到请求调用HandlerMapp ...
- 框架:SpringMVC的工作原理
SpringMVC的工作原理图: SpringMVC流程 1. 用户发送请求至前端控制器DispatcherServlet. 2. DispatcherServlet收到请求调用HandlerMa ...
最新文章
- python编程入门指南怎么样-python编程从入门到实践这本书怎么样
- 116.网络里的时延和带宽
- 单片机原理及其应用——单片机控制8只发光二极管交替闪烁
- 为什么线程池里的方法会执行两次_面试官问你java都有哪些线程池,自己是否自定义过线程池...
- 苏宁易购:公司改选董事 同意聘任张近东为公司名誉董事长
- 关于QT编译错误问题
- Kettle:创建资源库
- JAVA CLASS混淆工具:RetroGuard(已无法下载)
- hd计算机技术,BD和HD的区别是什么?
- 斗鱼封禁主播陈一发,新媒体有出路吗?
- matlab绘制那奎斯特曲线和bode图
- 清华大学 zhongguo li 计算机,2013年EI收录中国期刊名单(包括新收录的).xls
- 3.2-上位机与下位机的“私有协议”通信构架设计
- Google天气和股票API
- C语言练习题之标准电话号码(MOOC)
- 全球天气网(tianqi.com)天气预报调用插件
- lisp提取长方形坐标_如何利用lisp程序一次性提取CAD中点的坐标(不要点击每个点,太多了麻烦)...
- 在安装Centos时如何选择磁盘的分区?
- Bean named ‘userService‘ is expected to be of type ‘com.zkf.service.userServiecImpl‘ but[我的报错日常]
- X3850 X5 间歇性亮黄灯