Spring MVC:原理与使用

Posted E-HERO

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring MVC:原理与使用相关的知识,希望对你有一定的参考价值。

本人上一篇博文提到了Spring的注入功能,这样在存在对象依赖(具体意思可见上一篇博文)的时候就不用自己生成一个对象了,特别是对于较多的无状态对象的时候,这个特别方便,加上Spring提供的用xml配置文件和代码注解两种方式,使得使用更加灵活。然而spring的功能远不止如此,Spring的强大功能其实还在于做Java后台框架,即Spring MVC,把后台的逻辑和和视图解耦分离,方便使用与扩展,特别是在大型项目中很有用。

 

PS:卖个自己的广告,上一篇博文《Spring注入:配置与注解》 (如果是在其他抄袭网站看到这篇博文的人可以通过这个网址找到上一篇博文在哪里,这样会有一个比较连贯的了解,顺便吐槽一下这些抄袭网站,自己爬取别人的博文放到自己的网站上,还不写个引用自哪里,这终究不太好吧~~~http://blog.csdn.net/u011579138/article/details/51379066 

 

MVC

首先大概介绍一下什么是MVC,由于自己也是渣渣,所以为方便初学者学习,还是介绍一下自己理解中的MVC(不一定是完全对的,仅作参考,老鸟可以直接跳过这一段)。MVC是三个东西的缩写,modelviewcontroller

Model:业务模型类,例如:购物程序中一些包含用户信息的类,这些类只有getset的方法来获取值,或者经常提到service,就是那些不需要具体值的对象,只是进行方法调用的那些类,这些都属于model。可以简单理解为处理业务逻辑的类

View:给用户看的视图,例如html页面,jscss效果这些。简单理解就是给用户看的东西

Controller:控制器,这样描述可能不太好理解,例如,浏览器来了一个请求,这时候控制器(controller)就用来分发给具体业务模型(model),业务模型处理完之后返回一个视图(view)给用户,这就是一个完整流程。有初学者可能会控制器控制什么,例如一个url,其中传了个参数1可能是请求一个网页,参数2可能是请求另一个网页,这时候控制器就是用来把这个请求到底是交给哪个业务处理模型。

就像快递,用户寄一个快递,控制器(controller)拿到快递,根据用户的请求(参数),交给对应地区的快递员(model),快递员处理完发送任务之后返回一个结果(view)给用户,告诉用户我搞定了。这就是一个mvc的流程。

 


Spring MVC 原理

其实是基于servlet的一个框架,servlet可以理解为网页跟逻辑的映射的(具体还是请自学一下),spring是把所有的请求全部映射到一个叫DispatcherServlet的一个对象去,然后由这个对象进行分发请求,有点类似于controller的感觉。DispatcherServlet找到一个handler(这里其实是通过在一个叫handlerMappingsList对象中来找handlerExecutionChain,在这个handlerExecutionChain里面有handlerInterceptor,源码详情如果后面本人有空会写一篇博客来讨论源码实现,由于过于复杂,这里就不介绍了太多)。找到handler之后,这时候会通过handler找到HandlerAdapter,这里的handlerhandlerAdapter的区别,根据我查的几篇博客是这样说的handler负责找到需要处理这个请求的类,adapter负责找到这个类中具体哪个方法处理这个请求(以下两篇博客都是这样说的,第二篇中举的例子已经过时,里面那个adapter已经被官方废弃了)。

http://www.360doc.com/content/14/1024/23/18637323_419613178.shtml 

http://www.mamicode.com/info-detail-877142.html 

这里本人却并不赞同这个说法,后面本人会解释一下,这里先继续介绍spring MVC的流程,dapater找到之后会调用handle方法来调用处理这个请求的函数(即model)。一般这个函数会返回一些东西,经过conver的处理生成一个界面(即view),view生成好了就会返回给用户,这样一个处理流程就结束了。如下图所示

 

 HandlerHandlerAdapter真正的作用?

但是本人通过查看源码,发现并不是像这样,其实在handler的时候就已经确定了哪个具体的方法来处理这个请求。如下图,这里其实已经找到了对应的方法,downloadReportFile,所以这里并不是找到类,而且已经找到了类里面的方法了,而且这里的确定方法的标准其实就是判断urlhttp的方法(GET POST)。

 

其次,再看看adapter是怎么来的,是不是真的确定了具体的方法,先贴几张源码(这里不用慌,作为初学者担心看代码很烦或看不懂,慢慢静下心来,其实很容易看懂的,而且我会用详细的语言来表述,所以不要跳过这段)

这里可以看到通过getHandler得到了mappedHandler,其实mappedHandler是一个handlerExecutionChain(可以参考我上面那段提到的,如果文字太多可以用浏览器的ctrl+fhandlerExecutionChain那段)。找到之后检查handlermappedHandler是不是空,然后通过handler获得HandlerAdapter


再下一层,看看getHandlerAdapter的原理,从handlerAdapters这个容器中遍历,如果支持这个handler就返回相应的handlerAdapter(照顾初学者:logger是用来打log日志的工具,和代码逻辑无关)。

然后再下一层,看看spports里面是怎么实现的。可以看到就是判断了一下handler的类型,并且看supportsInternal的返回结果,很简单。

 

那么再下一层看看supportsInternal这个函数怎么实现,结果一看,就是返回true。所以你发现其实得到handlerAdapter其实和定位方法没有任何关系。


所以我才质疑handlerAdapter的作用究竟是什么。我有问过公司一个主管,结果发现他自己练spring本身的运行过程都不大清楚,所以也没有得到这个问题的答案。

这里的handlerAdapter有好3个,上面的源码是第一个的,但是后面两个我也看了,只是检查了一下是不是属于那些类型,也没有定位到具体的方法,也就是说handlerAdapter里面根本就没有用来指向哪个方法,指向具体的方法是在handler里面。

 

 

所以在这里个人猜测,handler是指向具体的方法,handlerAadpter是用来执行具体的方法的(在后面会看到,其实handlerAapter中有一个handler的方法,就是在这个方法中调用handler中指向的那个方法)


HandlerIntercetptor

这里顺便简单解释一下handlerIntercetptor的作用,这两个拦截器其实就是个事件触发机制,在handle这个请求前做一些事儿(HandlerExecutionChain中的applyPreHandle),在handle这个请求之后做些事儿(HandlerExecutionChain中的applyPostHandle),类似于Netty中的pipeline机制。也就是spring在让你处理请求前或请求后,你可以通过添加interceptor做一些处理。


HandlerExecutionChain

看名字顾名思义就是执行链,这里面包含了一个handlerInterceptor的容器,默认有两个interceptor,然后preHandle和postHandle都是空。如果自己要实现可以在里面自己添加自己的interceptor。然后这里面还包括了一个handler,上面已经说过了。

图中mappedHandler就是HandlerExecutionChain,先调用所有inteceptor的PreHandle,然后再调用adapter的handle函数,再调用所有interceptor的postHandle。其中如果applyPreHandle如果返回false,也就是事件处理完毕了,就是说不需要handler中那个函数去处理了,所以这个时候就会直接return,例如有些参数明显不合法,可以直接不作处理,如下图

 

 

Spring MVC 用法

了解完概念,再来介绍一下用法。这里的用法我只介绍用注解的方法,这种比较常用一些。Spring MVC中大部分的代码都已经写好了,自己需要做的就是需要写业务处理。

首先拦截请求,用注解注入一个类,在这个类中编写方法,用@RequestMapping注解,value就是uri,params就是参数,也可以再加个method,判断http的方法是GET还是POST,函数的体的参数和返回类型完全自己定义,没有特殊的格式。(一开始我总不清楚这些函数为什么要这么多参数,是不是固定要这些的,后来看了源码发现其实这些是用java反射做的,参数是不限制个数的那种函数申明方式,返回类型是object,所以这些返回类型和参数没有固定的)。不过一般可以定义自己需要的一些参数。

 

返回值的作用

没有@ResponesBody

没有这个注解,这注意返回的东西,是作为资源调用的标识使用,例如你返回一个a的string类型,会默认解析为找一个名字叫a的html或者js之类的资源文件。如果要返回其他类型,就得看看spring默认支不支持解析咯,有可能自己还要写解析的类,这个类就是ViewResolver,专门解析这些返回对象的(可以参见上面那个流程图中的第五步)。当然这里的资源都是静态的,如果需要一些动态的参数,这时候就要用到modelMap了(上面那个流程图也有,第六步),就是在ViewResolver处理之后再用到modelMap里面的一些值来动态处理。



有@ResponseBody

如果这个注解,就意味着返回的对象不是作为资源标识符来使用,而是作为http返回的包体内容。上面那种是属于你返回个东西,spring帮你解析成view了返回,这是把你返回的东西直接当做内容返回了。顾名思义ResponseBody。这里返回的内容也是需要解析,解析这个的叫converer,把返回的对象解析成可以放进http包体的内容。Spring默认支持了几种返回,例如string,json,还有byteArray(预知详情,自己可以试着看看源码)。所以如果你要返回一个你自己写的对象,那就要自己写个converer才行,不然最后没有返回的。

这就是大概的用法,其实Spring还有很多种用法,里面所支持的东西也还很多,例如可以和其他框架,像MyBatis或者Struts配合,但是本人能力有限,研究spring一周才勉强研究出这些东西,与其他框架配合也只做了一点与MyBatis相关的东西,以后若是有机会还是得多加练习才行。

另外ZZ再嘴多一点,照应开头所说的。其实Spring MVC也就是基于Servlet的,所以不用Spring MVC这种办法直接用Servlet也是可以实现网络请求处理的。而且spring通过大量调用判断其实是会牺牲掉一些性能的。但是依旧还是有人使用spring,其实就在于大型项目管理和维护比较比较方便一点这样逻辑会更清楚,因为这里将model,view,controller给分开了,处理逻辑和返回界面在不同的地方,如果用servlet势必会搅在一起。这大概就是spring的一个好处。但性能方面spring应该是处于劣势。

PS:本人是个渣渣,但是每次在研究完一个东西之后还是会总结一下这个框架有啥优势和不足,这样才是一个我这种渣渣提升的一个方向,所以万望诸君共勉。

 

因为前人,才能更高

Spring源码分析 http://www.360doc.com/content/14/1024/23/18637323_419613178.shtml 

PS:本篇博客主要根据ZZ本人查看源码和参考这篇博文,其他博文也有参考,但参考程度不多,故这里就不列举出来,但也很感激前人留下的文献,如有转发本文,请注明出处

http://blog.csdn.net/u011579138/article/details/51420185

 

以上是关于Spring MVC:原理与使用的主要内容,如果未能解决你的问题,请参考以下文章

Spring循环依赖那些事儿(含Spring详细流程图)

Spring MVC:原理与使用

Spring MVC:原理与使用

Spring MVC工作原理及源码解析 MVC原理介绍与IOC容器整合原理

深入解析Spring架构与设计原理-Web MVC的实现

Spring mvc 基本原理