读思码

日常记录


SpringMVC加载过程

<h1>从源码分析SpringMVC加载过程</h1> <h2>1.Dispatcherservlet的继承关系</h2> <p>Dispatcherservlet的继承关系是--&gt;FrameworkServlet(抽象类)--&gt;HttpServletBean(抽象类)--&gt;HttpServlet(抽象类)--&gt;GenericServlet--&gt;Servlet(接口)。servlet的生命周期是 init() doservice(){doGet(),doPost()}, doDestory().所以由这样的继承关系在加上servlet的生命周期,我们就可以知道,在tomcat容器在启动加载的时候回去执行init().但是在这个init()中又回去调用子类HttpServletBean的方法。</p> <p>servlet的生命周期开始于init()所以在加载容器的时候当然也是要从init开始,所以我就从dispatcherServlet最上层的实现类开始找,知道找到HttpServletBean,然后再看他的父类Httpservlet,httpservlet的父类genericServlet,最后是实现的一个servlet的接口。我从servlet的接口中找到了容器最开始加载的init()这个方法。这个时候我们去看genericServlet的时候发现只是对接口中的init方法进行了一个实现 但是具体的实现内容没有去做。我们再去看httpServlet这个继承了genericServlet的抽象类中没有init()这个方法。这个时候我们再去知道找到HttpServletBean中发现了一个被定义为final类型的init()方法。我们知道final类型的方法是不能被子类继承的,所以HttpServletBean的init()时加载开始的入口。 ![继承关系中的final init()](<a href="https://www.showdoc.cc/server/api/common/visitfile/sign/0753eaa8bae2a7db71927449c4619a78?showdoc=.jpg">https://www.showdoc.cc/server/api/common/visitfile/sign/0753eaa8bae2a7db71927449c4619a78?showdoc=.jpg</a> &quot;继承关系中的final init()&quot;)</p> <h2>2.web.xml配置</h2> <pre><code> &amp;lt;servlet&amp;gt; &amp;lt;servlet-name&amp;gt;springMVC&amp;lt;/servlet-name&amp;gt; &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt; &amp;lt;init-param&amp;gt; &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt; &amp;lt;param-value&amp;gt;classpath*:/applicationContext-mvc.xml&amp;lt;/param-value&amp;gt; &amp;lt;/init-param&amp;gt; &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt; &amp;lt;/servlet&amp;gt; &amp;lt;servlet-mapping&amp;gt; &amp;lt;servlet-name&amp;gt;springMVC&amp;lt;/servlet-name&amp;gt; &amp;lt;url-pattern&amp;gt;/&amp;lt;/url-pattern&amp;gt; &amp;lt;/servlet-mapping&amp;gt;</code></pre> <p>在web.xml文件中我们是这样配置springmvc的,加载的入口就是DispatcherServlet。 httpServletBean的init()这个方法是final,也就是这个方法是不能被集成的,因此我们就可以断定spring在做这里的时候,也就是初始化的时候的入口就是init方法,这个入口是不能被子类去实现的。init方法中执行了如下的操作:</p> <p>![init方法](<a href="https://www.showdoc.cc/server/api/common/visitfile/sign/c928f2a3826f00226f361c00b97ecb0f?showdoc=.jpg">https://www.showdoc.cc/server/api/common/visitfile/sign/c928f2a3826f00226f361c00b97ecb0f?showdoc=.jpg</a> &quot;init方法&quot;)</p> <p>try语句块中的代码是做一些跟springmvc配置文件,以及资源文件相关的初始化工作,相关的在web.xml文件中的配置相关的信息是在这里处理的,我们重点关注一下springmvc整体的初始化流程,让大家了解spring是如何加载的。好了我们看到initServletBean() ![initServletBean](<a href="https://www.showdoc.cc/server/api/common/visitfile/sign/76657f47d0cb59bb5bcade2840d9ef4b?showdoc=.jpg">https://www.showdoc.cc/server/api/common/visitfile/sign/76657f47d0cb59bb5bcade2840d9ef4b?showdoc=.jpg</a> &quot;initServletBean&quot;) 这时候我们发现在httpServletBean的这个类中有这个方法,但是没有实现而且是一个protocted修饰的方法,这也就是说这个需要子类去实现,好了我们顺着人家的代码进入freamWorkServlet中: <img src="https://www.showdoc.cc/server/api/common/visitfile/sign/c9f0d92c09476ed02631981f61161d1f?showdoc=.jpg" alt="" /></p> <p>此时的initServletBean()方法又是一个final限定的方法,跟httpservletBean中的init()方法是一样的,效果作用也一样我们就不再赘述。这里我们进入该方法的具体实现。我们发现这个时候在整个的方法中最关键的就是initWebApplicationContext()这个方法,我们大家对applicationContext应该是比较熟悉的,因为spring的容器其实就是一个context。这时候才是真正的开始容器的初始化。好了我们进入initWebApplicationContext()这个方法: <img src="https://www.showdoc.cc/server/api/common/visitfile/sign/399b1b37e7836f5b1400c2044c59bfcc?showdoc=.jpg" alt="" /> 在这个方法中代码的前两行,因为springmvc的基于spring的,所以第一步是首先要去获取parent父容器也就是spring的容器。然后开始根据父容器开始创建springmvc的容器。这里我们再进入下一步之前 我觉着有必要对createWebApplicationContext(parent)这块做一个简答 的解释:</p> <p><img src="https://www.showdoc.cc/server/api/common/visitfile/sign/7538bff5d7b1dfdf185756ee26ca0d25?showdoc=.jpg" alt="" /> 其实整个这个处理的效果或者用途就是用来将当前的springmvc的容器与他的父容器进行一个关联,比如wac.setParent(parent);wac.setServletContext(getServletContext());wac.setServletConfig(getServletConfig());wac.setNamespace(getNamespace());,最后将wac这个容器进行一个刷新。</p> <p>接下来我们返回上一步,说到的对springmvc的容器和他的父容器进行一个关联之后进行下一步的操作。 onRefresh(wac); <img src="https://www.showdoc.cc/server/api/common/visitfile/sign/3ef033e548db905886cc490c06459259?showdoc=.jpg" alt="" /></p> <p><img src="https://www.showdoc.cc/server/api/common/visitfile/sign/e4888b88e02fa51322f7b3c1a94254aa?showdoc=.jpg" alt="" /> 在frameServlet中的initWebApplicationContext方法中的第三行代码就是这句,但是我们在frameWorkServlet中看到onFresh同样是一个没有实现的方法,我们就应该可以推断的出来这个方法的具体实现应该交给他的子类去处理,这时候我们就要进入到他的子类dispatcherServlet中看到的是如下的实现: <img src="https://www.showdoc.cc/server/api/common/visitfile/sign/593c07abab1ac5a1205faf6c80c16536?showdoc=.jpg" alt="" /></p> <p>我们看到在dispaerServlet中的onRefresh()方法中只有一个简单的initStrategies()方法,看到这个词Strategies,这是策略的意思,到这里了跟大家说一下,springmvc中使用到的设计模式----策略模式。好了进入initStrategies()方法后,如上图,这个时候springmvc就开始去加载对应的一些模块中主要的组件,比如initMultipartResolver用来springmvc处理文件的上传,initLocaleResolver(context)用来处理国际话语言相关的一些操作(反正到目前为止我没有接触到。。。。)initThemeResolver().这个是用来处理一些有关动态更换样式的支持(主题)。好像也没有使用过。。。initHandlerMappings()这个很重要处理我们经常听到的有关url和controller的映射关系,initHandlerAdapters()处理映射有关的适配相关。initHandlerExceptionResolvers(context);springmvc有关异常的处理。initRequestToViewNameTranslator(context)处理请求到视图名称的一个转换。initViewResolvers()处理视图。</p> <h2>3.总结</h2> <p>对springmvc的整个的加载过程做一个简答的总结,在整个加载过程中httpServletBean是我们的入口,负责处理一些有关配置文件或者资源的准备,这是因为我们很多的bena有可能依赖这些资源,然后会开始servlet容器的创建工作从initServletBean()开始,这时候httpServletBean只是创建工作的入口,具体的创建是在他的子类frameWorkServlet中来做的,在frameWorkServlet中负责去跟父容器进行关联,并创建createWebApplicationContext。然后进入onRefresh()方法也就是他的子类dispaerServlet中取按照策略模式的方式对springmvc中的具体的每个模块进行初始化。所以在整个过程我们发现springmvc在做初始化的时候每个类所做的工作是不一样的,也是有分工的。httpservletBean主要是创建一些配置或资源文件,frameWorkServlet主要是创建容器以及跟父容器的关联。而在dispactorerServlet这个子类中才是真正的去做一些具体的初始化工作。</p>

页面列表

ITEM_HTML