接上一篇-springmvc源码分析开头片
上一节主要说了一下springmvc与struts2的作为MVC中的C(controller)控制层的一些区别及两者在作为控制层方面的一些优缺点。今天就结合下面的一张图和上一篇中关于springmvc各个模块之间及各个模块中的类的继承关系的一张图对springmvc的请求处理流程进行一个分析。当然有了springmvc的请求处理流程我们就知道了springmvc是如何在启动的时候去加载或者去解析对应的具体控制器,以及modleAndView使干什么用的,如何将controller处理后的结果映射到view中,也就是在我们java中的jsp或者freemaker中的。当然下面的这张图可能很多网友也有,但是可能每个人根据这张图的理解去分析的springmvc的原理都是不一样的(我只是结合这两张图我自己的一个理解)好了废话不多说咱们有图才有说服力。。。
这张图确实比较经典。首先我们大致的说一下:springmvc这个框架其实主要是有这几个大的模块组成的① dispatcherServlet ②handlerMapping③ controller④modelAndView⑤viewResolver⑥ view。当时这个springmvc的整个请求的流程不是加载的流程。对这个加载的流程做一个简答的介绍
①:DispatcherServlet是springmvc中的前端控制器(front controller),负责接收request并将request转发给对应的处理组件.
②:HanlerMapping是springmvc中完成url到controller映射的组件.DispatcherServlet接收request,然后从HandlerMapping查找处理request的controller.
③:Cntroller处理request,并返回ModelAndView对象,Controller是springmvc中负责处理request的组件(类似于struts2中的Action),ModelAndView是封装结果视图的组件.
④:视图解析器解析ModelAndView对象并返回对应的视图给客户端.
⑤:viewResolve是对我们的每个具体实现的controller封装后返回的modelAndView这个对象的解析处理,在这个根据我们配置的视图解析器将对应的modelAndView映射到对应的view(jsp或者其他的显示层语言)中去显示我们controller处理后返回到视图层的内容
⑥:显示每个controller返回的视图解析器的内容到对应的视图给客户端(view).
上面大致就是我们一个springnvc在发送一个get或者post的controller请求后再控制层的处理流程。
结合上面的请求处理流程,原本接下来应该是说一个在每个模块中也就是每一步是如何做的,但是在这里我想先去说一下加载的过程,也就是我们知道我们在使用springmvc的时候有时候我们使用配置文件的形式来配置,有时候使用注解的方式,但是大多数时候换是会采用注解的方式,这也是springmvc与struts2相比可以实现百分百零配置的优势所在。那么在我们不管是配置文件也好,是注解也好,我们知道springmvc的原生态的嵌入到我们的spring中的,那么在加载我们的spring文件的时候是如何加载springmvc的配置或者注解的呢?下面咱们从开始的地方来说一下:
首先大家不管是有没有去看过springmvc的源码,我想大家应该读知道我们在发送一个springmvc请求的时候是根据一个请求的去springmvc容器中去找跟这个url对应的具体的处理controller是哪个,找到后就去做业务处理,做完业务处理后封装一个modelandview 然后通知springmvc的viewResolve去对这个controller对应的modelAndView进行解析然后映射或者渲染到view中实现在客户端(这里一般是浏览器)上显示处理后的内容。但是这里我想大家都知道,那么springmvc的url和controller的对应关系是怎么建立的呢??
对于springmvc有了解的我想大家对spring也不陌生,因为springmvc原生态的支持spring。所以在spring启动加载容器的时候,也会去加载springmvc对应的controller的配置文件或者说注解。在spring加载完所有的bean的时候,springmvc会去遍历spring容器加载后的bean,然后根据我们的配置或者注解将controller上的url和对应的bean放到一个map中。这样我们就可以根据request请求中的url快速的定位到我们具体要使用的那个controller。这时候我们就有了两者的对应关系,但是这时候换需要我们去处理相关的参数信息。springmvc在处理参数信息的时候有两种方式,一种是在使用了@requestParam这个注解的时候,springmvc可以直接去将参数中的值和requestParam注解的参数进行一个绑定。如果不是使用的显示的注解方式,而是使用的根据参数名的方式映射绑定的话,那么springmvc在处理这样的参数的时候是使用的其他的工具类asm。这是因为java在做类的反射的时候只提供了获取方法参数类型的反射,并没有获取方法名的反射,因此这个时候springmvc在处理这个参数的绑定的时候,就使用asm的读取字节码的方式来获取方法名(asm这玩意是个操作字节码的框架,大家有兴趣的话可以去研究一下)。在这里两种方式跟大家说了,但是我要补充一下,如果你能使用注解的时候尽量使用注解,因为springmvc在使用asm框架去读取字节码的时候是很麻烦的也比较耗时,建议大家能使用@requestparam注解的尽量使用。
好了上面是对spring在加载springmvc相关控制器的时候是如何处理的做了一个大致的阐述。虽然不是很详细,但是总算有了对springmvc这个框架的一个整体的了解,这个时候我们再去分模块的去研究他。
下面先开始对dispatcherServlet的研究。
我们学过servlet的大家都知道,我们servlet的生命周期是 init() doservice(){doGet(),doPost()},doDestory().,我们看到dispatcherservlet的继承关系是--》frameWorkServlet--》httpServletBean--》httpServlet。所以由这样的继承关系在加上servlet的生命周期,我们就可以知道,在tomcat容器在启动加载的时候回去执行init().但是在这个init()中又回去调用子类的方法。这里我们截图看一下。
结合上面的这两幅图,我简单的做一个介绍。我们都知道servlet的生命周期开始于init()所以在加载容器的时候当然也是要从init开始,所以我就从dispatcherServlet最上层的实现类开始找,知道找到httpBeanServlet,然后再看他的父类httpservlet,httpservlet的父类genericServlet,最后是实现的一个servlet的接口。我从servlet的接口中找到了容器最开始加载的init()这个方法。这个时候我们去看genericServlet的时候发现只是对接口中的init方法进行了一个实现 但是具体的实现内容没有去做。我们再去看httpServlet这个继承了genericServlet的抽象类中没有init()这个方法。这个时候我们再去httpbeanServlet中发现了一个呗定义为final类型的init()方法。我们知道final类型的方法是不能被子类继承的,好了到这里我们终于找到了加载开始的入口。
----------今天我们找到了门,明天我们进门去一探究竟。明天晚上见^_^