一、springmvc初始化
我们使用springMVC的时候,它的主要入口时dispatcherServlet类,它最终实现了Servlet接口。Servlet初始化执行init()方法,其中执行到springMVC子容器初始化的会调用DispatcherServlet的onRefresh()方法,而在onRefresh()方法中只做了一件事,就是调用initStrategies()方法来初始化springMVC的九大组件。
initStrategies直译过来就是初始化策略,而springMVC把九大组件设计成就打策略,其实就是为了去明确各个组件的职责,达到解耦的目的。按照springMVC九大组件的初始化顺序,他们分别是MultipartResolve多文件上传组件、LocaleResolver多语言支持组件、ThemeResolver主题模板处理组件、HandlerMappings URL映射组件、HandlerAdapters业务逻辑适配组件、HandlerExceptionResolvers异常处理组件、RequestToViewNameTranslator视图名称提取组件、ViewResolvers视图渲染组件、FlashMapManager内存管理组件。如图:
下面详细分析一下每个组件的功能和职责。
1.MultipartResolver
它主要是支持多文件上传,如代码所示。它主要的逻辑就是将enctype为"multipart/form-data"的表单请求request封装成MultipartHttpServletRequest的对象,那程序员在开发的时候就只需要调用MultipartHttpServletRequest的getFile方法就可以获取客户端上传的文件列表了。
2.LocaleResolver
它主要是用于支持国际化,多语言切换的组件,而LocaleResolver的主要作用就是从request中解析出local参数的值,如源码所示。resolveLocale方法它是从request中去解析出local而setLocal()方法是将指定的local值设置到request中,local对象大多数情况下都是用来做国际化处理的,一般会配合多语言字典properties来使用。例如中国的Local值为zh_CN。
3.ThemeResolver
他主要是支持web页面的多主体风格切换,可以通过ThemeResolver来读取和解析页面的主题样式配置,它的实现原理和LocaleResolver类似,也是配置一套properties文件,然后根据不同的参数来切换读取。当然,使用ThemeResolver也可以实现国际化。如源码所示。它的主要方法和LocalResolver也类似。一个是从request中去提取主题名称的方法,一个是设置主题名称的方法。
4.HandlerMappings
它主要是用来保存url和业务逻辑的对应关系,它本质上是一个Map,它的key是url,值就是对应Controller中配置了@RequestMapping注解的方法,但是这种关系呢在spring源码中被封装成一个叫做HandlerMapping的对象,然后每个HandlerMapping对象都被缓存到一个List中,如源码所示。
5.HandlerAdapters
它主要的功能是动态解析参数以及动态适配业务逻辑对应的Handler,如源码所示。在HandlerAdapter中它提供了一个叫做handle()的方法,它的第三个参数Object handler就是指业务逻辑处理器,也就是HandlerMapping。
handle()方法在DispatcherServlet中的doDispath()方法中被调用,而handler对象就是根据用户请求Url从handlerMapping的缓存List中去获取到的HandlerMapping对象,在HandlerAdapter的handle()方法中首先回去动态解析用户传过来的参数,并且会完成数据类型的转换,然后会反射调用HandlerMapping封装的Controller中的方法,最后会将调用方法的返回值封装为一个叫做ModelAndView的对象。
6.HandlerExceptionResolvers
它主要是用于拦截对不同异常的个性化处理,spring可以给不同的异常配置不同的ModelAndView,而HandlerExceptionResolver就是根据异常类型将处理封装为一个ModelAndView,从而将异常转化为更加友好的web页面展示。如源码所示。在HandlerExceptionResolver组件中只有一个方法就是将异常转化为ModelAndView,当HandlerExceptionResolver自己发生异常的时候或者在异常页面渲染过程中发生异常的时候HandlerExceptionResolver他不会进行处理,但是spring提供了一个全局的配置可以去设置500页面或者是404页面来处理这个问题。
7.RequestToViewNameTranslator
这个组件的主要功能是从request中去提取viewName,而这个viewName它可以设置在url参数上也可以设置在request的header上。如源码所示。这个其实挺有意思,就是将request的请求转化为视图名称。它只有一个getViewName()方法。
8.ViewResolvers
就是根据视图名称找到视图对应的模板文件,然后进行解析。如源码所示。ViewResolver组件只有一个resolveViewName()方法,我们可以看到resolveViewName()方法中有两个参数,第一个参数是viewName,他是string类型它其实就是视图名称对应的模板文件的名称。第二个参数是local,前面我们讲过它代表的是本地语言环境,它可以用来做国际化。而resolveViewName()方法的返回值是一个View对象,View对象就是用来渲染的,也就是将程序返回的结果填入到具体的模板里面生产具体的视图文件,比如说jsp,ftl,html等待。
9.FlashMapManager
它相当于一个参数缓存器可以用来去保证请求跳转过程中参数不会丢失,和struts2中的ValueStack值栈非常类似,主要是redirect重定向的时候参数传递会丢失,这时候FlashMapManager就能够大显身手,它可以实现Redirect重定向也能和Forward转发同样的效果。如源码所示。FlashMapManager主要有两个方法,一个是retrieveAndUpdate()方法它是用来恢复参数的,而且会将恢复的和超时的参数删除掉。第二个是saveOutputFlashMap()方法,它是用来保存参数的,FlashMapManager会默认将参数保存到session中。在日常开发中如果不想将参数暴露在url路径中,如果不想将参数暴露在url路径中那就一个在请求转发时在参数上添加@RedirectAttributes注解将参数缓存起来然后在下一个处理器中就可以获取到。
注意:ModelAndView和View并不属于MVC的九大组件之中,ModelAndView只是对ViewName和Model的封装然后作为返回值把信息反馈给用户,并且它并没有包含任何的执行逻辑。而view呢而是对模板的封装他是用作参数来传递。
二、springMVC请求执行流程
我们使用springMVC的时候,它的主要入口时dispatcherServlet类它最终实现了Servlet接口,那它就是个Servlet类。请求该方法会执行doService方法。请求来了,那接下来springMvc执行流程用图表示
- 用户向服务端发送一次请求,这个请求会先到前端控制器DispatcherServlet(也叫中央控制器)。
- DispatcherServlet接收到请求后会调用HandlerMapping处理器映射器。由此得知,该请求该由哪个Controller来处理(并未调用Controller,只是得知)
- DispatcherServlet调用HandlerAdapter处理器适配器,告诉处理器适配器应该要去执行哪个Controller
- HandlerAdapter处理器适配器去执行Controller并得到ModelAndView(数据和视图),并层层返回给DispatcherServlet
- DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图。
- DispatcherServlet将模型数据填充到视图中
- DispatcherServlet将结果响应给用户