<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    對(duì)Spring MVC Framework的理解

    Posted on 2005-05-27 11:29 李嵐 閱讀(3321) 評(píng)論(3)  編輯  收藏 所屬分類: Java

    前言

    最近在看Spring MVC的源碼,就把自己對(duì)MVC模式和對(duì)各種框架的實(shí)現(xiàn)的認(rèn)識(shí)寫出來給大家看看,算是一個(gè)總結(jié).所以,懇請(qǐng)大家用懷疑的眼光來看待這篇文章,假如有認(rèn)識(shí)不對(duì)的地方,麻煩指出.

    MVCWEB應(yīng)用

    MVC是什么就不用我多說了.對(duì)于現(xiàn)有較成熟的Model-View-Control(MVC)框架而言,其注意的主要問題無外乎下面這些:

    Model:

    模型應(yīng)該包含由視圖顯示的數(shù)據(jù).J2EE Web應(yīng)用中,數(shù)據(jù)通常應(yīng)該由普通的javabean組成.一旦一個(gè)控制器選擇了視圖,模型就要包含視圖相應(yīng)的數(shù)據(jù).模型本身不應(yīng)該進(jìn)一步的訪問數(shù)據(jù),也不應(yīng)該和業(yè)務(wù)對(duì)象相聯(lián)系.

    模型要解決的問題包括:

    l          封裝要顯示的數(shù)據(jù)

    l          我不認(rèn)為模型要依賴于特定的框架

    l          不一定非得是javabean

    View:

    視圖負(fù)責(zé)顯示出模型包含的信息,視圖不必了解控制器或是底層業(yè)務(wù)對(duì)象的具體實(shí)現(xiàn)

    視圖要解決的問題包括:

    l          在顯示給定數(shù)據(jù)模型的情況下顯示內(nèi)容

    l          不應(yīng)該包含有業(yè)務(wù)邏輯

    l          可能需要執(zhí)行顯示邏輯,比如顏色交替的顯示某個(gè)數(shù)組的各行

    l          視圖最好不處理驗(yàn)證的錯(cuò)誤,數(shù)據(jù)的驗(yàn)證應(yīng)該在由其他組件完成

    l          視圖不應(yīng)該處理參數(shù),參數(shù)應(yīng)該交由控制器集中處理

    Control:

    控制器就好像MVC里的中樞神經(jīng),它也許會(huì)需要一些助手來幫助它比如解析視圖,解析參數(shù)等.控制器可以訪問到業(yè)務(wù)對(duì)象或者是它的代理是很重要的,比如Struts里的Action.

    控制器要解決的問題包括:

    l          檢查和抽取請(qǐng)求參數(shù)

    l          調(diào)用業(yè)務(wù)對(duì)象,傳遞從請(qǐng)求中獲取的參數(shù)

    l          創(chuàng)建模型,視圖講顯示對(duì)應(yīng)的模型

    l          選擇一個(gè)合適的視圖發(fā)送給客戶端

    l          控制器有時(shí)不會(huì)只有一個(gè)

    現(xiàn)有的框架

    現(xiàn)在已經(jīng)有很多的MVC的框架實(shí)現(xiàn).比較流行的應(yīng)該就是StrutsWebwork

    Struts

    這是最流行的web框架,幾乎成為了實(shí)際上的工業(yè)標(biāo)準(zhǔn).除了上面討論的MVC模式應(yīng)該有的優(yōu)點(diǎn)以外.它還有如下一些缺點(diǎn):

    l          每個(gè)Action只生成一次,然后就被緩存起來,再次請(qǐng)求這個(gè)Action的時(shí)候就不會(huì)生成新的對(duì)象,而是重復(fù)使用第一次生成的對(duì)象,這就意味著每個(gè)Action必須是線程安全的

    l          采用ActionForm封裝了表單數(shù)據(jù),但是卻只能對(duì)應(yīng)String類型的數(shù)據(jù), 雖然它可以使用工具Commons Beanutils進(jìn)行類型轉(zhuǎn)化,但是僅僅是提供了對(duì)象級(jí)別的支持

    l          嚴(yán)重的依賴于Servlet API, 測(cè)試比較困難(不過下一版Struts里的Action.execute的方法簽名講會(huì)換成execute(ActionContext actionContext),依賴也許不會(huì)那么嚴(yán)重)

    l          框架本身的驗(yàn)證規(guī)則比較簡(jiǎn)單,一般都是依賴于Commons Validation進(jìn)行驗(yàn)證

    l          想在Action前后做些處理很困難.有時(shí)甚至不得不自己去寫專門的控制器

    l          由于Struts都是具體的類繼承,這樣很容易打破封裝?

    l          提供各式各樣的自定義的標(biāo)簽,但是數(shù)據(jù)綁定太原始了,這樣就使頁(yè)面代碼依賴于Struts這個(gè)特定的框架,而它卻不是規(guī)范,我覺得這是很致命的

    l          它太面向JSP,盡管使用其他視圖技術(shù)是有可能的,但是使用的時(shí)候卻不是很方便

    Webwork

    這個(gè)框架雖然我沒使用過,但是卻一直在關(guān)注它的發(fā)展

     

    Webwork的設(shè)計(jì)思想采用了比Struts更為聰明的一種方式,就技術(shù)角度上說比Struts要高出不少.它以Command模式為基礎(chǔ).分為XworkWebwork,而且框架并不依賴于Servlet API.

     

    Xwork提供了很多核心功能:攔截器(Interceptor,運(yùn)行時(shí)表單驗(yàn)證,類型轉(zhuǎn)換,IoC容器等.

     

    WebWork建立在Xwork之上,用于處理基于HTTP的響應(yīng)和請(qǐng)求.MapActionContext封裝了Session,Application等這些Servlet對(duì)象.從而解除了和Servlet API的耦合.

     

    但是它仍然不是完美的:

    l          為每一個(gè)請(qǐng)求都創(chuàng)建一個(gè)Action可能有些浪費(fèi).(但是Servlet引擎也是為每個(gè)請(qǐng)求創(chuàng)建多個(gè)對(duì)象,但是也沒看出來對(duì)性能有多大的影響?)

    l          當(dāng)項(xiàng)目越來越大的時(shí)候,配置文件可能會(huì)很零亂.好像它不支持多個(gè)配置文件

    l          異常處理是Command模式里值得注意的問題:我們不知道某一特定命令可能會(huì)拋出什么特定的異常,所以execute()被迫拋出異常,而不論異常是運(yùn)行時(shí)異常,還是已檢查異常

     Spring MVC Framework的目標(biāo)

    上面說了一些MVC的原理,以及現(xiàn)在主流框架的一些問題,現(xiàn)在來看Spring是如何處理的. Spring MVC框架根據(jù)不同的角色定義了很多接口,但是它最大的問題也是依賴于Servlet API

    Spring MVC Framework有這樣一些特點(diǎn):

    l          它是基于組件技術(shù)的.全部的應(yīng)用對(duì)象,無論控制器和視圖,還是業(yè)務(wù)對(duì)象之類的都是java組件.并且和Spring提供的其他基礎(chǔ)結(jié)構(gòu)緊密集成.

    l          不依賴于Servlet API(目標(biāo)雖是如此,但是在實(shí)現(xiàn)的時(shí)候確實(shí)是依賴于Servlet)

    l          可以任意使用各種視圖技術(shù),而不僅僅局限于JSP

    l          支持各種請(qǐng)求資源的映射策略

    l          它應(yīng)是易于擴(kuò)展的

    我認(rèn)為評(píng)價(jià)一個(gè)框架,應(yīng)該有幾個(gè)原則

    l          它應(yīng)該是易于使用的,易于測(cè)試的

    Spring 易于使用嗎?我不這么覺得,尤其是它的配置文件.在最恐怖的情況下,各種業(yè)務(wù)邏輯,基礎(chǔ)設(shè)施也許會(huì)擁擠在一個(gè)配置文件里.而如事務(wù)處理這些基礎(chǔ)設(shè)施應(yīng)該是由容器管理而不是開發(fā)人員,就算把這些分開到幾個(gè)配置文件里,邏輯上雖然清晰了,但是基礎(chǔ)設(shè)置卻還是暴露在外邊

    Spring易于測(cè)試嗎?對(duì)Spring進(jìn)行單元測(cè)試很容易,測(cè)試起來很方便

    l          應(yīng)該在多個(gè)層次上提供接口

    Spring提供了很多接口,而幾乎每個(gè)接口都有默認(rèn)的抽象實(shí)現(xiàn),每個(gè)抽象實(shí)現(xiàn)都有一些具體實(shí)現(xiàn),所以在可擴(kuò)展性這點(diǎn)上Spring無疑是很優(yōu)秀的

    l          框架內(nèi)部和框架外部應(yīng)該被區(qū)別對(duì)待

    框架內(nèi)部可以很復(fù)雜,但是使用起來一定要簡(jiǎn)單,Spring的內(nèi)部比較麻煩,但是它很好的隱藏了這種復(fù)雜性,使用起來很舒服,比如設(shè)置一個(gè)bean的屬性.僅僅是setPropertyValue(String propertyName, Object value)就完成,至于怎么去設(shè)置,Spring完全隱藏了這種復(fù)雜性

    l          完善的文檔和測(cè)試集

    這個(gè)就不用說了,老外的東西,都很完善

     Spring Web框架基本流程

    知道了Spring MVC框架,現(xiàn)在來看看它的流程

    Spring MVC Framework大至流程如下:

    當(dāng)web程序啟動(dòng)的時(shí)候,ContextLoaderServlet會(huì)把對(duì)應(yīng)的配置文件信息讀取出來,通過注射去初始化控制器DispatchServlet. 而當(dāng)接受到一個(gè)HTTP請(qǐng)求的時(shí)候, DispatchServlet會(huì)讓HandlerMapping去處理這個(gè)請(qǐng)求.HandlerMapping根據(jù)請(qǐng)求URL(不一定非要是URL,完全可以自定義,非常靈活)來選擇一個(gè)Controller. 然后DispatchServlet會(huì)在調(diào)用選定的ControllerhandlerRequest方法,并且在這個(gè)方法前后調(diào)用這個(gè)Controllerinterceptor(假如有配置的話),然后返回一個(gè)視圖和模型的集合ModelAndView.框架通過ViewResolver來解析視圖并且返回一個(gè)View對(duì)象,最后調(diào)用Viewrender方法返回到客戶端

    DispatcherServlet

    這是框架的控制器,是一個(gè)具體類,它通過運(yùn)行時(shí)的上下文對(duì)象來初始化.控制器本身并不去控制流程,而只是是Controller控制器”,他只是把處理請(qǐng)求的責(zé)任委托給了對(duì)應(yīng)的Controller.

     

    控制器繼承自抽象基類FrameworkServlet,它的屬性webApplicationContext就代表著這個(gè)web程序上下文,而這個(gè)上下文對(duì)象默認(rèn)實(shí)現(xiàn)就是從一個(gè)XML文件讀取配置信息(當(dāng)然也可以是其他文件格式). WebApplicationContext其實(shí)是beans包的東西,這個(gè)包提供了這個(gè)Spring整個(gè)框架的基礎(chǔ)結(jié)構(gòu),以后我會(huì)分析這個(gè)包的內(nèi)容.但是現(xiàn)在僅僅需要知道WebApplicationContext代表一個(gè)web應(yīng)用的上下文對(duì)象.

     

    現(xiàn)在來看看DispatchServlet是如何工作的:

    DispatchServlet由于繼承自抽象基類FrameworkServlet,FrameworkServlet里的doGet(),doPost()方法里有調(diào)用serviceWrapper(),跳到serviceWrapper()里去看,結(jié)果發(fā)現(xiàn)它有把具體實(shí)現(xiàn)委托給了doService(request, response); 方法.所以現(xiàn)在已經(jīng)很清楚了, DispatchServlet真正實(shí)現(xiàn)功能的是doService() 這個(gè)方法.

     

    特別的, FrameworkServletinitFrameworkServlet()這個(gè)方法是控制器的初始化方法,用來初始化HandlerMappings之類的對(duì)象,這也是延遲到子類實(shí)現(xiàn)的.其實(shí)就是一個(gè)Template模式的實(shí)現(xiàn).don’t call us, we will call u.總的看來,Spring就是通過這樣來實(shí)現(xiàn)它的控制反轉(zhuǎn)的:用框架來控制流程,而不是用戶

     

    跳到doService()一看究竟,就會(huì)發(fā)現(xiàn)真正工作的又是另一個(gè)助手函數(shù)doDispatch(request, response),沒辦法,繼續(xù)看下去,發(fā)現(xiàn)這樣兩行代碼

    HandlerExecutionChain mappedHandler = null;

             mappedHandler = getHandler(processedRequest, false);

    HandlerExecutionChain源碼就發(fā)現(xiàn)它其實(shí)就是對(duì)Controller和它的Interceptors的進(jìn)行了包裝;

     

    getHandler()就是從HandlerMappings(這是一個(gè)List,存放的handlerMapping對(duì)象)中取出對(duì)應(yīng)的handlerMapping對(duì)象, 每個(gè)HandlerMapping對(duì)象代表一個(gè)ControllerURL的映射(其實(shí)在運(yùn)行的時(shí)候是一個(gè)HandlerExecutionChainURL的映射,HandlerExecutionChain對(duì)象其實(shí)就是對(duì)Controller和它interceptors的一個(gè)包裝器,可以把HandlerMapping看成ControllerURL的映射).而這個(gè)HandlerMapping是通過配置文件在運(yùn)行時(shí)注射進(jìn)來的,一般是SimpleUrlHandlerMapping這個(gè)子類

     

    取得了HandlerMapping對(duì)象,繼續(xù)向下看,發(fā)現(xiàn):

                      if (mappedHandler.getInterceptors() != null) {

                                                   for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {

                                                            HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];

                                                            if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {

                                                                     triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

                                                                     return;

                                                            }

                                                            interceptorIndex = i;

                                                   }

                                         }

    這里就是在調(diào)用Controller的攔截器,原理就是這句了:

             interceptor.preHandle(processedRequest, response, mappedHandler.getHandler(), mv);

    preHandle方法傳入了mappedHandler.getHandler()這個(gè)參數(shù)來實(shí)現(xiàn)遞歸調(diào)用! interceptor.postHandle方法如此一般.只不過這個(gè)方法是在handleRequest方法后調(diào)用

     

    繼續(xù)看下去:

             HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

             mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    發(fā)現(xiàn)ControllerhandleRequest真正的操作又被代理給了HandlerAdapterhandle方法,并且返回一個(gè)ModelAndView,我想這里增加一層的意義應(yīng)該是為了解除ControllerDispatchServlet的耦合吧.

     

    接著就很簡(jiǎn)單了,調(diào)用render()方法,在這個(gè)方法里面由ViewResoler解析出視圖名,再調(diào)用視圖對(duì)象的render方法把合適的視圖展現(xiàn)給用戶

     

    到此,控制器的流程就OVER

    HandlerMapping

    通過使用HandlerMapping,控制器可以用URL和某一個(gè)Controller進(jìn)行標(biāo)準(zhǔn)的映射,而實(shí)現(xiàn)URL映射的具體子類的UrlHandlerMapping.

     

    Spring還允許我們自定義映射,比如通過Session,cookie或者用戶狀態(tài)來映射.而這一切僅僅只需要實(shí)現(xiàn)HandlerMapping接口而已.不過URL映射已經(jīng)能滿足大部分的要求

    Controller

    Controller 類似StructsAction, Controller接口只有一個(gè)方法handleRequest(),放回一個(gè)ModelAndView對(duì)象,如同設(shè)計(jì)目標(biāo)所說的那樣,每個(gè)Controller都是一個(gè)java組件,所以它可以在上下文環(huán)境中任意配置,組件屬性都會(huì)在初始化的時(shí)候被配置.Spring自己提供了幾個(gè)具體的實(shí)現(xiàn).方便我們使用

    ViewResolver

    Controller通常返回包含視圖名字而不是視圖對(duì)象的ModelAndView對(duì)象.從而徹底的解除了控制器和視圖之間的耦合關(guān)系,并且在這里還可以提供國(guó)際化的支持.

    在你的配置文件中你可以:

    welcomeView.class = org.springframework.web.servlet.view. InternalResourceView

    welcomeView.url=/welcome.jsp

    也可以

    welcomeView.class = org.springframework.web.servlet.view.xslt. XsltView

    welcomeView.url=/xslt/default.xslt

     

    View

    這也是一個(gè)java組件,它不做任何請(qǐng)求處理或是業(yè)務(wù)邏輯,它僅僅獲取模型傳遞的數(shù)據(jù),并把數(shù)據(jù)顯示出來.它里面的 render方法按照如下流程工作:

    l          設(shè)置模型的數(shù)據(jù)到request作用域

    l          取得視圖的URL

    l          轉(zhuǎn)發(fā)到對(duì)應(yīng)的URL

    總結(jié):

    Springweb框架是一個(gè)很優(yōu)秀的框架,在這里只是走馬觀花的分析了Spring的工作流程和一些關(guān)鍵的類,但是并沒有去深入的去探討它背后所體現(xiàn)的思想,還有它的優(yōu)缺點(diǎn)等東西.這些都等下次再說吧

     

    這里再次說明一下,上面說的只是我自己的想法,假如有不理解或者不正確的地方,請(qǐng)?jiān)谙旅媪粞灾赋龌蛘卟榭垂俜降?/SPAN><Spring-Reference>,以后會(huì)逐漸推出自己對(duì)Spring其他的理解

    Feedback

    # re: 對(duì)Spring MVC Framework的理解  回復(fù)  更多評(píng)論   

    2005-11-10 12:40 by pesome
    寫的很不錯(cuò)啊,我現(xiàn)在才開始學(xué)spring

    # re: 對(duì)Spring MVC Framework的理解  回復(fù)  更多評(píng)論   

    2006-04-03 16:35 by 朱吉赟
    你依然那么蒸蒸日上。

    我手機(jī)丟了,QQ密碼忘了,差點(diǎn)與世隔絕了。

    你最近怎么樣?

    我的新QQ:85604123

    # re: 對(duì)Spring MVC Framework的理解  回復(fù)  更多評(píng)論   

    2008-01-11 11:39 by bizairshop
    看來spring mvc不是我的理想框架 航服推薦 http://www.bizairshop.com

    # re: 對(duì)Spring MVC Framework的理解  回復(fù)  更多評(píng)論   

    2013-05-28 14:03 by JAVA22222
    看來spring mvc不是我的理想框架

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     

    posts - 7, comments - 23, trackbacks - 0, articles - 0

    Copyright © 李嵐

    主站蜘蛛池模板: 日本精品久久久久久久久免费 | 老牛精品亚洲成av人片| 亚洲色无码一区二区三区| 午夜视频在线观看免费完整版| 亚洲av综合av一区二区三区| 免费萌白酱国产一区二区| 97性无码区免费| 免费在线中文日本| 亚洲六月丁香婷婷综合| 免费人成网站在线高清| 啦啦啦高清视频在线观看免费| 国产亚洲成在线播放va| 亚洲日本VA中文字幕久久道具| 亚洲AV中文无码乱人伦| 日本a级片免费看| 天天摸天天操免费播放小视频| 男人天堂免费视频| 一级做a毛片免费视频| 免费高清A级毛片在线播放| 亚洲人成未满十八禁网站| 亚洲精品中文字幕无乱码麻豆| 亚洲精品国产精品乱码不卞| 久久国产高潮流白浆免费观看| 亚洲AV无码一区二区三区网址| 亚洲AV中文无码乱人伦下载| 亚洲午夜久久久久妓女影院| 亚洲人成影院在线观看| 免费一级毛片不卡不收费| 男女免费观看在线爽爽爽视频| 免费毛片毛片网址| 亚洲国产精品成人久久久| 亚洲图片中文字幕| 亚洲丰满熟女一区二区v| 亚洲av永久无码精品三区在线4| 亚洲精品亚洲人成在线观看下载| 99ee6热久久免费精品6| 91精品国产免费久久国语蜜臀| 国产亚洲综合视频| 黄色一级毛片免费| 一区二区免费电影| 国内永久免费crm系统z在线|