SpringMVC流程全解析(2)

接着分析DispatchServlet,按照惯例,依旧贴出一张清晰醒脑的大图,这张图清晰的描绘了关于DispatchServlet的类继承关系,如下:


DispatchServlet.png

还是先从web.xml的配置说起,从上面的关系图中我们可以看出DispatchServlet实际也是一个实现了Servlet标准接口的类,所以要想web应用正常跑,我们必须在web.xml中注册这个Servlet,如图:


web.png

在开始分析DispatchServlet之前,我想跟大家细细的讲讲Servlet。Servlet主要是用来处理客户端请求并封装响应结果通过其内部的service方法发送给客户端,如图中所示:
servlet.png

其实从这张图就可以看出,Sevlet是有一个生命周期的,并且它从创建到销毁都是在一个Servlet容器中进行的。在SpringMVC中Servlet的框架是由两个java包组成的:javax.servlet和javax.servlet.http;javax.servlet中定义了一套标准化的servlet类都必须实现或者扩展的通用接口和类。javax.servlet.http中定义了基于Http通讯的实现,当Web容器接收到servlet请求时,不管是get,put还是别的,它会把请求封装成一个个的HttpServletRequest对象,然后传给Servlet#service方法进行处理,最后返回一个HttpServletResponse对象返回。关于Servlet容器的销毁,其实servlet容器会先调用servlet#destroy方法,先销毁servlet对象以及与其关联的ServletConfig对象,最后再实现容器的关闭。

扩展点:从一开始的那种类继承关系图中我们可以看出,如果我们想定义我们自己的Servlet对象,我们完全可以学着SpringMVC的方式继承HttpServlet,但切记写完之后要在web.xml中注册。

1.关于DispatchServlet的初始化

按照套路,我们得先看HttpServlet的Init方法,因为这个Init方法是Servlet容器记载Servlet类的数据到内存中的开始,它首先会创建一个ServletConfig对象,然后在创建一个Servlet对象,最后调用这个Init方法将Servlet对象与ServletConfig关联起来进行初始化的操作,而在SpringMVC中这个方法的实现在HttpServletBean中,如图:


HttpServletBean.png

看下其HttpServletBean#Init方法的逻辑:


HttpServletBean#Init.png

实现流程如下:
1.获取在web.xml中配置servletConfig参数(也就是在init-param配置项中的参数)的并且进行封装及验证,通过校验missingProps来验证某些参数的必要性,如果有些missingProps项没有初始化的话,将抛出异常(内部细节读者可自行查阅);

2.将当前这个servlet转为BeanWrapper,使Spring对其能进行一些属性的填充;
3.通过ResourceLoader对配置资源进行解析(也就是我们在web.xml中配置的springmvc的配置文件);
4.InitServletbean方法留给子类扩展的,其主要在FrameworkServlet进行实现,也就是为了对servletBean进行初始化;


InitServletbeanMethod.png

InitServletbean.png

InitServletbean主要干了两件事,初始化WebApplicationContext以及FrameworkServlet。

2.WebApplicationContext的初始化

来看initWebApplicationContext,贴上代码,一步一步分析:

initWebApplicationContext.png

流程如下:
1.先去根据servletContext对象获取最上层的WebApplicationContext,这个地方不懂的请看之前写过的SpringMVC流程全解析(1);
2.判断当前WebApplicationContext是否被创建过,如果是,那么将其设置到rootContext,并且对已经创建的WebApplicationContext进行配置及刷新(这一步咋们在后面细说);
config&refresh.png

3.如果没有被创建过,那么通过servlet的contextAttribute查找ServletContext中对于的属性,默认是WebApplicationContext.class.getName()+".ROOT",也就是ContextLoaderListener加载时创建的XmlWebApplicationContext实例来进行查找。

扩展:这个地方我们其实可以重写这个初始化的逻辑来创建我们自己的WebApplicationContext,但是必须要在web.xml中创建初始化contextAttribue的key值,SpringMVC中默认是WebApplicationContext.class.getName()+".ROOT";

如果上面还是没法获取到,那就只能根据ContextLoaderListener创建的rootContext进行创建了。通过servlet的初始化参数contextClass,如果没有配置的话就是XmlWebApplicationContext.class,然后通过反射实例化WebApplicationContext,然后将其与ContextLoaderListener创建的XmlWebApplicationContext关联,同时获取contextConfigLocation属性,并配置在servlet初始化参数中。最后根据创建的XmlWebApplicationContext初始化Spring环境,加载配置文件。
4.使用AbstractApplicationContext的refresh方法进行配置文件的加载,这是个模板方法,实现逻辑在DispatchServlet中,主要是根据WebApplicationContext刷新spring在web功能中所必须使用的全局变量。

initStrategies.png
initStrategies.png

到了这一块,我们得结合着我们得SpringMVC配置文件进行讲解了,我得让你清晰的知道为啥SpringMVC配置文件就得这么配置。

1.initMultipartResolver,initLocaleResolver,initThemeResolver

这是SpringMVC用来处理文件上传的,当然,要使用它,并不是以下这一处配置,你还必须在Web应用的上下文中添加对应的MultipartResolver,也是是在controller的方法开头添加,这样springMVC才会对它进行处理。代码如下:


multipartResolver.png

我们的配置文件内容:


Paste_Image.png

简单解释下,CommonsMultipartResolver是SpringMVC默认的文件解析器,如果要想自定义,继承这个类做些实现即可,关于property属性,这些都在CommonsFileUploadSupport定义好的,CommonsMultipartResolver继承了CommonsFileUploadSupport这个类。
关于initLocaleResolver,initThemeResolver与initMultipartResolver实现方式基本大同小异,SpringMVC都有默认的实现类,查看DispatchServlet.properties可以看到。
Paste_Image.png

2.HandlerMapping

当客户端发出请求时,DispatchServlet会将请求提交给HandlerMapping,然后HandlerMapping根据WebApplicationContext的配置来回传给DispatchServlet相应的Controller,按照惯例,依旧按照代码讲述。

Paste_Image.png

1.默认情况下,它会去加载当前系统中所有实现了HandlerMapping接口的bean,如图所示:


handlerMapping.png

2.但是我们可以在web.xml文件中配置detectAllHandlerMappings为false,那样就会只加载我们在Springmvc配置文件中加载的HandlerMapping了。

detectAllHandlerMappings.png
RequestMappingHandlerMapping.png

此时,SpringMVC将会查找为handlerMapping的bean,作为当前系统唯一的handlerMapping。

Paste_Image.png

如果没有定义的话,那么就会去找在DispatchServlet.properties文件中定义的HandlerMapping了,SpringMVC默认是以BeanNameUrlHandlerMapping作为映射策略的实现。


Paste_Image.png

扩展点:这个地方其实可以通过重写DispatchServlet#getDefaultStrategies自定义HandlerMapping策略。

好了,今天就讲到这里,最后总结下,其实springMVC流程看起来还是很清晰,但是我们要学会透过这个流程去看内部的实现,去看SpringMVC中一些好的设计点,好的实现方式。这些我决定在写完这个系列文章的最后给大家再总结。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,022评论 6 528
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 97,760评论 3 412
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 174,687评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,318评论 1 307
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,112评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,645评论 1 320
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,724评论 3 435
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,885评论 0 285
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,387评论 1 330
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,368评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,506评论 1 365
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,063评论 5 355
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,759评论 3 343
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,150评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,414评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,080评论 3 386
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,494评论 2 370

推荐阅读更多精彩内容