溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么深入分析Spring MVC framework

發(fā)布時(shí)間:2021-10-27 09:29:12 來源:億速云 閱讀:94 作者:柒染 欄目:編程語言

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)怎么深入分析Spring MVC framework,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

在當(dāng)今的MVC framework里,似乎Webwork2逐漸成為主流, Webwork2+SpringFramework的組合變得越來越流行。這似乎意味著Spring自帶的MVC framework遠(yuǎn)比Webwork2差,所以大家紛紛用Webwork2來代替。確實(shí),Spring的MVC framework不算是整個(gè)Spring的核心部件,但它的威力卻超過了很多人的想象。很多人包括xiecc認(rèn)為Spring的MVC framework是非常優(yōu)秀的,甚至比Webwork2更優(yōu)秀。

下面列舉一下Spring的MVC framework在設(shè)計(jì)時(shí)做出的一些重要的決定,并將之和相關(guān)的MVC framework如Webwork2或struts進(jìn)行對(duì)比:

一.Spring的整個(gè)MVC配置是基于IOC容器的

與struts或webwork2相比,這是一個(gè)ms有點(diǎn)奇怪的決定,看一下Spring MVC的配置文件,***看到的不是action或者form,而是一些有著特定名字的bean,Bean下面的配置是一些簡(jiǎn)單或有點(diǎn)復(fù)雜的屬性。我們看到的是機(jī)器更容易的數(shù)據(jù)結(jié)構(gòu),而不是人更容易理解的元素。

但是這恰恰是Spring的MVC強(qiáng)大的根源!因?yàn)樗呐渲镁褪荢pring的核心IOC容器的配置,這意味著所有IOC容器的威力都可以在這里展現(xiàn),我們可以為所欲為地對(duì)Spring MVC進(jìn)行擴(kuò)展和增強(qiáng),我們可以完成在其它MVC framwork中很多難以想象的任務(wù)。想擴(kuò)展新的URL映射方式嗎?要換一個(gè)themeResolver或LocalReolver的實(shí)現(xiàn)嗎?想在頁面中顯示新類型的View(比如說RDF,呵呵,一個(gè)小秘密:xiecc是研究語義網(wǎng)的,雖然成天不務(wù)正業(yè),不寫論文,只寫八卦)?甚至想直接在 Controller里定義AOP嗎?這些對(duì)Spring的MVC來說都是小菜一碟。

我沒有仔細(xì)研究過Webwork2的擴(kuò)展機(jī)制,我知道通過Webwork2的interceptor機(jī)制,可以進(jìn)行很多的擴(kuò)展,甚至有一個(gè)簡(jiǎn)單簡(jiǎn)單的IOC容器。但不管它有多強(qiáng)大,提供了多少擴(kuò)展點(diǎn)。它的威力都很難和真正的IOC容器相比。而struts的plugin功能則是出名的濫,雖然它也提供了plugin機(jī)制。

Spring采用IOC配置的另一個(gè)原因是使Spring的MVC與Spring的IOC容器的整合變得非常的容易。Spring提供了與 struts與webwork2的整合,但是這樣整合都需要在進(jìn)行間接的包裝,感覺總不是很自然。而且還會(huì)導(dǎo)致一個(gè)概念多個(gè)配置,webwork2就需要在Spring里配置bean,再配置自己的xwork文件。想象一下吧,我們的bean直接就是一個(gè)controller,直接可以完成MVC的所有任務(wù),這是多少爽的感覺。

Rod Johnson采用IOC容器來實(shí)現(xiàn)的另一個(gè)原因是這會(huì)減少好多開發(fā)工作量??匆幌聈rlMapping吧,它提供的property本身就是一個(gè) HashMap,只有配置完成,我們的bean里的數(shù)據(jù)就自然存在了,哈哈,好爽吧。不用象struts那樣解析XML,再把它的內(nèi)容一項(xiàng)一項(xiàng)地讀到 HashMap里。

雖然這樣的配置會(huì)有點(diǎn)怪異,但假如我們對(duì)Spring的IOC容器非常熟悉的話,會(huì)發(fā)現(xiàn)它非常的親切,也非常的簡(jiǎn)單。

***是一個(gè)簡(jiǎn)單的小秘密,Spring怎么知道某個(gè)bean的配置就是urlMapping?另一個(gè)bean的配置就是 viewResolver?其實(shí)很簡(jiǎn)單,把所有的bean全部讀到內(nèi)存里,然后通過bean的名字或類型去找就行了。通過名字去找就是簡(jiǎn)單的 getBean方法,通過類型去找則使用了BeanFactoryUtils.beansOfTypeIncludingAncestors的靜態(tài)方法。

二.Spring提供了明確的Model,View概念和相應(yīng)的數(shù)據(jù)結(jié)構(gòu)

在Spring里有一個(gè)有趣的數(shù)據(jù)類型叫做ModelAndView,它只是簡(jiǎn)單地把要顯示的數(shù)據(jù)和顯示的結(jié)果封裝在一個(gè)類里。但是它卻提供了明確的MVC概念,尤其是model概念的強(qiáng)化,使程序的邏輯變得更清晰了。

記得以前在Struts里寫程序里的時(shí)候,為了顯示數(shù)據(jù)經(jīng)常自己把東西放到HttpSession或HttpServletRequest里(或set到form里,雖然不太有用),這造成了model概念的模糊,而且也導(dǎo)致了struts與JSP頁面的緊耦合。假如我們要替換成 Veloctiy,就得另外加一個(gè)plugin,因?yàn)樵趘elocity里數(shù)據(jù)是不需要不放到request里的。

Webwork2里強(qiáng)調(diào)的是與Web framework解耦和它的command模式的簡(jiǎn)單性,因此在它的action里只有簡(jiǎn)單的get或set方法,假如返回?cái)?shù)據(jù),也只是簡(jiǎn)單地返回一個(gè) String.當(dāng)然這樣的實(shí)現(xiàn)有它的好處,但是它淡化了model和view的概念。Rod Johnson認(rèn)為Webwork2里的Action同時(shí)包含了Action和Model的職責(zé),這樣一個(gè)類的職責(zé)太多,不是一個(gè)很好的設(shè)計(jì)。當(dāng)然 Jason Carreira不太認(rèn)同這種觀點(diǎn),因?yàn)锳ction里的model對(duì)象完成可以delege給其它對(duì)象。但不管怎樣,這種爭(zhēng)論的根源在于 Webwork2里淡化了model, view甚至web的概念。仁者見仁,智者見智,***的結(jié)果還是看個(gè)人喜歡好吧。

三.Spring的Controller是Singleton的,或者是線程不安全的

和Struts一樣,Spring的Controller是Singleton的,這意味著每個(gè)request過來,系統(tǒng)都會(huì)用原有的 instance去處理,這樣導(dǎo)致了兩個(gè)結(jié)果:我們不用每次創(chuàng)建Controller,減少了對(duì)象創(chuàng)建和垃圾收集的時(shí)間;由于只有一個(gè) Controller的instance,當(dāng)多個(gè)線程調(diào)用它的時(shí)候,它里面的instance變量不是線程安全的。

這也是Webwork2吹噓的地方,它的每個(gè)Action都是線程安全的。因?yàn)槊窟^來一個(gè)request,它就創(chuàng)建一個(gè)Action對(duì)象。由于現(xiàn)代JDK垃圾收集功能的效率已經(jīng)不成問題,所以這種創(chuàng)建完一個(gè)對(duì)象就扔掉的模式也得到了好多人的認(rèn)可。Rod Johnson甚至以此為例證明J2EE提供的object pool功能是沒多大價(jià)值的。

但是當(dāng)人們?cè)诖祰u線程安全怎么怎么重要的時(shí)候,我想請(qǐng)問有多少人在多少情況下需要考慮線程安全?Rod Johnson在分析EJB的時(shí)候也提出過其它問題,并不是沒有了EJB的線程安全魔法,世界就會(huì)滅亡的,大多數(shù)情況下,我們根本不需要考慮線程安全的問題,也不考慮object pool.因?yàn)槲覀兇蠖鄶?shù)情況下不需要保持instance狀態(tài)。

至少我寫了那么多的struts Action,寫了那么多的Spring Controller,幾乎沒有碰到需要在instance變量保持狀態(tài)的問題。當(dāng)然也許是我寫的代碼不夠多,Struts的設(shè)計(jì)者Craig R. McClanahan曾經(jīng)說當(dāng)時(shí)他設(shè)計(jì)struts時(shí)有兩個(gè)條件不成熟:當(dāng)時(shí)沒有測(cè)試驅(qū)動(dòng)開發(fā)的概念;當(dāng)時(shí)JVM的垃圾收集性能太次。假如現(xiàn)在重新設(shè)計(jì)的話,他也會(huì)采用每個(gè)request生成一個(gè)新對(duì)象的設(shè)計(jì)方法,這樣可以解決掉線程安全的問題了。

四.Spring不象Webwork2或tapestry那樣去隱藏Servlet相關(guān)的元素如HttpServletRequest或HttpServletResponse

這又是一個(gè)重要的設(shè)計(jì)決定。在Webwork2里我們沒有HttpServletRequest或者HttpServletResponse,只有g(shù)etter, setter或ActionContext里數(shù)據(jù),這樣的結(jié)果導(dǎo)致一個(gè)干凈的Action,一個(gè)與Web完全無關(guān)的Action,一個(gè)可以在任何環(huán)境下獨(dú)立運(yùn)行的bean.那么Webwork2的這樣一個(gè)基于Command模式的Action究竟給我們帶來了什么?我想主要有兩點(diǎn):

1.它使我們的Action可以非常容易地被測(cè)試。

2.用戶可以在Action里添加業(yè)務(wù)邏輯,并被其它類重用。

然而仔細(xì)跟Spring比較一下,我們就會(huì)發(fā)現(xiàn)這兩點(diǎn)功能所帶來的好處其實(shí)并不象我們想象的那么顯著。Spring的Controller類也可以非常輕松被測(cè)試,看一下spring-mock下面的包吧,它提供的MockHttpServletRequest, MockHttpServletResponse還有其它一些類讓測(cè)試Controller變得異常輕松。再看一下Action里的業(yè)務(wù)邏輯吧,Jason Carreira曾經(jīng)說我們可以盡情地在Webwork2的Action里加業(yè)務(wù)邏輯,因?yàn)锳ction是不依賴于Web的。但是有多少人真正往 Action里加業(yè)務(wù)邏輯的?大多數(shù)人都會(huì)業(yè)務(wù)邏輯delegate給另一個(gè)Service類或Manager類。因?yàn)槲覀兒芮宄鵄ction里加業(yè)務(wù)邏輯會(huì)使整個(gè)體系的分層架構(gòu)變得不清晰,不管怎樣,Web層就是Web層,業(yè)務(wù)層就是業(yè)務(wù)層,兩者的邏輯混在一起總會(huì)帶來問題的。而且往Action里加業(yè)務(wù)邏輯會(huì)使用這個(gè)Action類變得龐大,Webwork2的Action是每個(gè)request都創(chuàng)建實(shí)例的,盡管帶來的性能影響不太大,但并不表示每次都要把業(yè)務(wù)邏輯再new出來,業(yè)務(wù)邏輯在大多數(shù)的情況下應(yīng)該是單例的。

不把request和response展現(xiàn)給用戶當(dāng)然還會(huì)帶來功能上的損失,也許一般的場(chǎng)合,用用webwork2提供的接口已經(jīng)足夠了,但有時(shí)我們必須要知道request和response才能發(fā)揮出更大的威力。比如我以前的一個(gè)項(xiàng)目里有一個(gè)通過遞歸動(dòng)態(tài)生成的樹狀結(jié)構(gòu)的頁面,在jsp頁面上顯示遞歸是痛苦或不可能的,因此我用response直接write出頁面,這在spring里很easy,但在webwork里可能比較難了(偶不敢肯定,偶研究得不夠深,也許高手是有辦法的)。

五.Spring提供了不錯(cuò)但不夠充分的interceptor機(jī)制

回頭看一下struts,它在架構(gòu)里甚至沒有給我們提供hook point的機(jī)會(huì),我們沒有任何機(jī)會(huì)加入自己的interceptor.我們只能通過重載struts的RequestProcessor類來進(jìn)行一點(diǎn)有限的擴(kuò)展。

到了Webwork2,似乎interceptor一下子成了整個(gè)Framework的核心,除了Action的核心部件,其它所有的東西都是 interceptor.它的超強(qiáng)的interceptor功能使們擴(kuò)展整個(gè)架構(gòu)變得非常方便。有人稱這種interceptor為AOP,Jason Carreira則自豪地宣稱這個(gè)叫做pragamtic AOP.我不認(rèn)同這是AOP,它只是簡(jiǎn)單的interceptor機(jī)制。但不管如何,它的interceptor確實(shí)有強(qiáng)大的功能。

Spring也提供了它的interceptor機(jī)制,它的HandlerInterceptor三個(gè)interceptor方法:peHandle, postHandle, afterCompletion.分別對(duì)應(yīng)Controller執(zhí)行前,Controller執(zhí)行后和page render之后。雖然大多數(shù)情況下已經(jīng)夠用,但是從功能上來說顯然它沒有Webwork2強(qiáng)大。從AOP的角度來看,它沒有提供around interceptor,而只有before與after interceptor.這意味著我們無法在interceptor前后保持狀態(tài),最簡(jiǎn)單的情況假如我們要計(jì)算一個(gè)Controller的執(zhí)行時(shí)間,我們必須在執(zhí)行完before后把begintime這個(gè)狀態(tài)保持住,再在after里把它調(diào)出來,但是顯然這個(gè)狀態(tài)保持會(huì)是個(gè)問題,我們不能把它放到 instance變量里,因?yàn)閕nterceptor不是線程安全的。也許通過ThreadLocal可以解決這個(gè)問題,但是如此簡(jiǎn)單的功能要用到這樣的方法來處理,顯然這個(gè)Interceptor本身設(shè)計(jì)上還是有點(diǎn)問題的。

六.Spring提供了MultiActionController,使它可以在一個(gè)類里包含多個(gè)Action

這個(gè)設(shè)計(jì)和struts的DispatchAction有點(diǎn)類似,只不過提供了更靈活的機(jī)制。當(dāng)我們的項(xiàng)目變大的時(shí)候,把功能類似的方法放到同一個(gè)Action里完全值得的!Webwork2缺少這樣的機(jī)制。假如看一下Spring的源代碼,會(huì)發(fā)現(xiàn)其實(shí)實(shí)現(xiàn) MultiActionController的工作量相當(dāng)?shù)纳?,只不過是用反射機(jī)制把解析出來的方法名執(zhí)行一下就完事了。其實(shí)Webwork2也完全可以提供這樣的機(jī)制。雖然從設(shè)計(jì)上來說確實(shí)不是很優(yōu)雅,但是它確實(shí)很有用。

七.Spring提供了更多的選擇方式

看看Spring里提供的Controller吧,它提供了好多不同的Controller類。要生成Wizard嗎?要專門用于提交form 的Controller嗎?要執(zhí)多個(gè)方法的類嗎?Spring提供了豐富的子類來擴(kuò)展這些選擇。當(dāng)然我們還可以很輕松地自己擴(kuò)展這些功能。

再看看Spring的ViewResolver吧,它提供了無數(shù)不同類型的ViewResolver.更重要的是我們自定義我們的頁面映射方式??纯磗trtus,看看webwork2,都會(huì)存在頁面與 forward name的一層間接轉(zhuǎn)換,我們必須在配置文件里配置好某個(gè)字符串(典型的是success)對(duì)應(yīng)的是那個(gè)頁面。但是Spring里我們有了更大的自由度,我們可以采用webwork2的策略,也可以采用更簡(jiǎn)單的策略,如將JSP文件名去掉擴(kuò)展名的映射方法。也許有人認(rèn)為這種映射方式很幼稚,但是我覺得它是非常有用的方式,即使在大項(xiàng)目里。

還有新的擴(kuò)展嗎?看看Spring Web Flow吧,它是SpringFramework的子項(xiàng)目。它為一長(zhǎng)串的基于頁面流的Wizard頁面提供了可配置的實(shí)現(xiàn)方式。在Spring 1.3里,它將是SpringFramework的一部分。

八.Spring的tag

盡管Spring的tag數(shù)量上少得可憐,但它卻是精心設(shè)計(jì)的。它的目標(biāo)很簡(jiǎn)單:讓美工可以輕松地編輯頁面。因?yàn)樵赟pring的頁面里 Text仍然是Text,checkbox仍然是CheckBox,而不象在struts或webwork2中的Tag.它只是用Springbind對(duì)輸入內(nèi)容進(jìn)行了一下包裝。所以盡管頁面顯示代碼上會(huì)比Webwork2多,但這絕對(duì)是有價(jià)值的。

在接下來的幾章里,我會(huì)分析一下Spring是如何讓我們的Web應(yīng)用不需要知道ApplicationContext就能夠訪問IOC容器的,然后會(huì)對(duì)Spring的設(shè)計(jì)和執(zhí)行過程進(jìn)行簡(jiǎn)單的源碼分析,然后給出幾個(gè)擴(kuò)展Spring MVC的方法。

上述就是小編為大家分享的怎么深入分析Spring MVC framework了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI