SpringMvcソースコードの調査(2)DispatchServletの初期化

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して12日目です。クリックしてイベントの詳細をご覧ください

コンテンツ

SpringMvcソースコードの調査(1)Tomcatがプロジェクトを開始したときにSpringは何をしますか

序文

前回の記事では、彼のInitizlizedのContextLoaderListenerでwebApplicationContextを作成し、それをservletContextに配置することについて説明しました。tomcatが起動して実行されると、リスナーに入る最初のメソッドに加えて、サーブレットも1つずつ作成されます。サーブレットのライフサイクルを覚えておいてください。最初のメソッドはinitメソッドであり、次のメソッドは1つずつ読み取られます。

まず、Initメソッドがどこにあるかを特定する必要があります。ここでは、DispatchServletを見てみましょう。image.pnginitの最初のメソッドは存在しません。次に、彼の親クラスFrameworkServletを見てみましょう。image.pngこのクラスでは見つかりませんでしたが、親クラスHttpServletBeanになりました。image.png当然のことながら、ここではInitメソッドが実装されており、ブレークポイントに到達する場所を見つけて、これがエントリであるかどうかを判断し、読み取りを開始します。image.pngOK、ブレークポイントが入っています。これが入り口であることを確認してから、コードを読む公式の旅を始めてください。

正式に開始

initメソッド

image.pngこのコードは比較的単純です。propertyValuesは、サーブレットタグから取得した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存在的。

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の最初のメソッドについては、名前を見るとその機能を確認できます。詳細に興味がある場合は、自分で読むことができます。ざっと見てみると、BeanはApplicationContextを介して取得され、DispatchServletのメンバー変数に配置されていることがわかりました。

私はこれを見ました、親指を立てて行ってください、宝物〜

結びの言葉

記事を書く目的はあなたがあなたの知識を統合するのを助けることです。あなたはコメントエリアで悪いことや間違ったことを指摘することができます。記事を読んで、それがあなたに役立つと思うなら、親指を立てることができます。疑問がある質問を見つけた場合、または理解できない場合は、コメントしてWeChatに追加してください。すべてを知れ。もちろん、みんなと友達になって、お互いに学びたいです。

おすすめ

転載: juejin.im/post/7086367269978128398