SpringMvc源码探秘(二)DispatchServlet初始化

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

目录

SpringMvc源码探秘(一)Tomcat启动项目时Spring做了什么

前言

在上一篇文章中,我们讲到了在ContextLoaderListener中,他的Initizlized中创建了一个webApplicationContext放入了servletContext中。在tomcat启动运行时,除了第一个方法会进入listener中,还会去挨个创建Servlet,还记得Servlet的生命周期吗,第一个方法就是init方法,接下来方法一个一个阅读。

首先先要定位Init方法在哪里,这里先看下DispatchServlet中。 image.png 一众init开头的方法中并没有存在,接下来看他的父类FrameworkServlet。 image.png 在这个类中也没有发现,接着翻父类HttpServletBean。 image.png 不出所料,这里实现了Init方法,找到地方了打个断点确定一下是否是这个入口,我们开始阅读。 image.png OK了,断点进来了,确定这里就是入口,接下来开始正式的阅读代码之旅吧。

正式开始

init方法

image.png 这一段代码比较简单,propertyValues是从servlet标签中获取的init-param标签中的数据。我们这里没有设置,所以此处获取不到也就不会进入下方的If中。 image.png 接下来这里是一个模版方法,由子类去实现的,在FrameworkServlet中有实现,我们这里要阅读一下。

initServletBean

image.png 通过查看这个代码,除了打印日志,只有这个initWebApplicationContext是关键方法了,我们点击进去查看一下。

initWebApplicationContext

方法一段一段看,先来看第一段。 image.png 这一段代码比较简单,创建了两个变量,一个是rootContext,一个是wac,类型都是WebApplicationContext,值得关注的是,rootContext被赋值,通过ServletContext中获取了一个WebApplicationContext,这里大概率获取到的就是ContextLoaderListener中创建的那个。

image.png 这一段代码中判断当前类的一个属性是webApplicationConetxt是否非空,这里其实是空的,因为我们当前的类刚刚创建,这里的属性值是没有被赋值的,If代码片段不会进入。

image.png wac此时为空,会进入当前If,进入findWebApplicationContext方法。

findWebApplicationContext

image.png 看上方代码,可以看出来关键在于getContextAttribute方法能否获取到值。 image.png image.png 这里可以看出,contextAttribute默认值为null,那么我们这里没有进行赋值时,他还是为null。此时该方法返回null,所以该方法返回null。

回到上一层代码。 image.png 因为刚刚的查找没有找到,所以这里要创建一个了,把rootContext传进去了,应该是作为parent存在的。

扫描二维码关注公众号,回复: 13789694 查看本文章

createWebApplicationContext

image.png 这个代码比较清晰,第一行获取了ApplicationContext的一个class,大概率是从web.xml中获取,然后不存在的话,返回一个默认的。随后在下面的代码中就实例化了一个applicationCotext。然后给context设置环境信息、上级、以及configlocation。然后调用了configureAndRefreshApplicationContext方法。这个方法看名字是去执行refresh方法的。最后返回了出去,随后我们跟进configureAndRefreshWebApplicationContext方法中看一下。

configureAndRefreshWebApplicationContext

image.png 这一段代码没有什么实际意义,设置了一个Id值。

image.png 这一段代码设置一些属性值,也没有什么实际的参考意义。值得注意的是,这段代码的最后一行,添加了一个事件监听器,根据名字可以看到监听的是ContextRefreshEvent,这里先放下后面有用。

image.png 调用了一个initPropertySources属性,看名字,这个方法里面做的是,把servletConfig当作propertySource,后面要获取property的时候,从servletConfig中获取。

image.png 这里没什么东西,主要的是refresh方法,也就是SpringBean那一套东西,这里执行完成后就一路返回到initWebApplicationContext的后续代码了。我们接着往下看。

initwebApplicationContext

image.png 接下来,到这一段,通过代码调试,发现这个值为True,那么这里取反就跳过了。

image.png 成员变量publishContext通过查看,默认值为true。这里所的操作其实也就是把刚刚创建出来ApplicationContext放到了ServletContext中,防止重复创建。
随后就返回了最后的方法。

疑问

这个时候我产生了一个疑问,因为我之前也度过一些关于源码解读的文章,都有说过,HandlerMapping、HandlerAdapter、ViewResolver这些东西,随后我就疑惑怎么在这里没有看到呢,在自我怀疑,是我漏掉了什么吗,我带着问题寻找了一下。

init开头的一些方法

在DispatchServlet中发现了一些端倪。在DispatchServlet中有一些init开头的方法。 image.png

onRefresh方法

发现这不就是我想要的一些东西吗,但是他们并没有被调用呀。这个时候我要查看一下他们的调用关系,得出下图。 image.png 发现OnRefesh方法,恍然大悟,知道在哪里遇到过了。 image.png 但是在这里时,我是经过调试的,这个RefreshEventReceived是等于True的。那么我意识到,有哪些地方修改了这个属性的值,于是乎我看到了一个熟悉的东西。

事件监听

image.png 看这个方法,把RefreshEventReceived设置为True后,也调用了onRefresh方法。到了这里也看明白了,一切都串起来了。还记得在之前创建applicationContext的方法中,向applicationContext中追加了一个ContextRefreshListener。 image.png 看了一下这个监听器,监听的是ContextRefreshEvent,这个事件在Spring完成refresh方法的最后一步,会发起一个事件广播,也就是contextRefreshEvent。 image.png OK了,到这里就清晰了。把以前学到的东西也都串起来了。

告一段落

这一篇文章到这里就结束了,关于DispatchServlet里面的init开头的方法,大家看名字就知道是干嘛的了,如果对里面的细节感兴趣的话,可以自行往里阅读。我粗略的看了一眼,都是通过ApplicationContext获取Bean,然后放入DispatchServlet的成员变量中。

都看到这了,点个赞再走呗,宝~

结束语

写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。

猜你喜欢

转载自juejin.im/post/7086367269978128398
今日推荐