SpringMVC流程全解析(2)

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


SpringMVC流程全解析(2)_第1张图片
DispatchServlet.png

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


SpringMVC流程全解析(2)_第2张图片
web.png

在开始分析DispatchServlet之前,我想跟大家细细的讲讲Servlet。Servlet主要是用来处理客户端请求并封装响应结果通过其内部的service方法发送给客户端,如图中所示:
SpringMVC流程全解析(2)_第3张图片
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,贴上代码,一步一步分析:

SpringMVC流程全解析(2)_第4张图片
initWebApplicationContext.png

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

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

1.initMultipartResolver,initLocaleResolver,initThemeResolver

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


SpringMVC流程全解析(2)_第7张图片
multipartResolver.png

我们的配置文件内容:


SpringMVC流程全解析(2)_第8张图片
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,按照惯例,依旧按照代码讲述。

SpringMVC流程全解析(2)_第9张图片
Paste_Image.png

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


SpringMVC流程全解析(2)_第10张图片
handlerMapping.png

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

SpringMVC流程全解析(2)_第11张图片
detectAllHandlerMappings.png
RequestMappingHandlerMapping.png

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

SpringMVC流程全解析(2)_第12张图片
Paste_Image.png

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


Paste_Image.png

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

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

你可能感兴趣的:(SpringMVC流程全解析(2))