1.為什么要使用框架?
(1)框架自動完成了很多瑣屑的任務
對于Struts2來說,它幫助我們方便地完成了數據類型轉換、數據驗證、國際化等等
Web開發中常見的任務。還有Spring中大量使用的Template模式,都是在讓我們的開發
過程更加自動化、智能化。使用框架就是避免重新發明輪子,重新復制這些模板代碼。
框架讓我們將精力更多地放在更高級別的問題上,而不是常見工作流和基礎任務上。
(2)使用框架就是優雅地繼承了框架背后的架構
框架背后的架構通常定義了一系列的工作流程,我們要做的就是將特定應用的代碼
依附到這套流程上,這樣就可以享受到框架帶來的種種好處了。有些時候我們也可以
反抗框架的架構規則,但框架通常以一種很難被拒絕的方式提供它的架構。如此簡單
就可以優雅地繼承一個優秀的架構,而且是免費的,何樂而不為呢?
(3)使用框架更容易找到訓練有素的人
我之前所在公司整個項目幾乎都沒有用過什么框架,從Service服務的查找(類似JNDI)
到日志打?。愃芁og4j),再到數據庫連接池(類似DBCP),全都是內部人員自己
實現的。一來是因為項目比較老,當時可能還沒有什么開源框架可供使用,二來也是因為
公司保守的策略,擔心使用不穩定的開源框架可能會給項目帶來風險。這在當時的環境下
也許是沒錯的,公司高層自然會從更大的視角來考慮整個項目。
但是當項目逐漸龐大起來,同時世界上優秀的開源框架越來越多時,如果不能及時重構
并引入一些成熟的開源框架,最后的結果可能就是新招來的開發人員必須從頭開始學習
這個復雜的系統(都是內部系統,網上也沒有文檔幫助),還要小心內部框架的種種Bug,
成本真是太高了。
(4)內部框架跟不上行業的發展
前面說到了內部框架的Bug。對于開源框架,可能會有框架創始者團隊、大批的開源愛好者、
開源社區來支持。人民的力量是無窮的,Bug的修復速度可想而知,這點從最近開源后的
TextMate的Bug修復進程就可以看出了。很多擱置了很久的Bug在開源后被愛好者們迅速
解決,而內部框架呢?在當初開發他的人員離開公司后,在沒有重大Bug時甚至都不會有人
去讀他的源代碼吧,差距可見一斑!
(5)當然使用框架也不是一本萬利的事情
前面也提到過,使用不成熟的框架是有風險的,對于一個不是那么激進的項目還是保守為好。
(除非這是一群自由沒拘束的技術狂熱分子,可以自行決定使用什么框架,那真是幸福的事)
就像我以前用過的Java的HA高可用性服務Sequioa一樣,這個框架最終不再被開發公司提供支持
了,這時風險就更大了。
此外,使用一些不常見的框架時還要注意框架源碼的License協議,不要在項目中隨意引用、
修改框架的源碼以免引起不必要的法律糾紛。
2.Struts2背后的架構
既然前面已經分析了框架的這么多好處,那我們自然會開始學習使用Struts2了。但使用Struts2
會繼承什么樣的優雅架構呢?其實從較高的抽象層次上看,它依然是我們熟悉的MVC模式。
對應之前HelloWorld的例子來看,
控制器C
(FilterDispatcher)也就是我們在web.xml中聲明的
Struts2核心類。而
模型M
就是我們的NewsAction動作類。而
視圖V
自然就是news.jsp了。模型
的概念似乎有些模糊,什么是模型呢?其實這個聽起來很名詞的概念在Struts2中既包含了靜態
從Web前端傳來的業務數據,也包含了業務邏輯的實現。
有人可能會說這種架構沒什么新意嘛,MVC框架有很多,這跟其他框架有什么區別呢?讓我們
站在低一級別的抽象層次上解剖Struts2,看看它有什么與眾不同。
乍看十分復雜,如果只從用戶角度來看,在開發時我們只需要實現
黃色
的部分,也就是我們
HelloWorld實例中的struts.xml,NewsAction和news.jsp。這就是我們要做的全部,就如前面
說的,只需要做很少的事情,我們就成為了這個優秀架構的一部分。
現在來看其他部分。FilterDispatcher就是我們配置在web.xml中的Servlet過濾器,這是Struts2
的入口,所有Struts2的Web應用都要這樣配置。接下來
藍色
和
綠色
的部分就是Struts2的核心
了,可以說這些類都是Struts2的開發人員精心設計架構的。
(1)客戶端發送請求,J2EE容器解析HTTP包,將其封裝成HttpServletRequest。
(2)FilterDispatcher攔截到這個請求,并根據請求路徑到ActionMapper中查詢決定調用哪個Action。
(3)根據ActionMapper的返回結果,FilterDispatcher委托ActionProxy去struts.xml中找到這個Action。
(4)ActionProxy創建一個ActionInvocation,開始對Interceptor和Action進行遞歸調用。
(5)各個Interceptor完成各自任務
(6)真正對Action的調用,返回結果路徑
(7)Result對象將返回數據輸出到流中
(8)返回HttpServletResponse給J2EE容器,容器發送HTTP包到客戶端。
這就是Struts2的執行流程,核心對象是ActionInvocation和Interceptor,以及還未介紹的ActionContext。
ActionInvocation是整個流程的總調度,它跟Spring AOP中的Invocation對象很像。而Interceptor有很多
都是Struts2自帶的,最重要的是保存請求參數,并將前臺的數據傳遞到Action的成員變量上。
而ActionContext就是保存這些數據的全局上下文對象,最重要的是用來保存Action實例的ValueStack。
所謂全局是指ActionContext可以在Action以及Result中訪問,其實它是ThreadLocal類型。每個請求線程
都會有自己的Action和ActionContext實例。
可以說學習Struts2主要就是學習:
(1)讓Interceptor和Action配合完成任務。
(2)將前臺數據保存到Action中。
(3)Result通過ValueStack從Action中得到返回數據。
3.Struts2與Struts1的不同點
從上面的執行流程已經可以看出Struts1和2的巨大區別。
(1)ActionForm哪去了?Action還是那個Action嗎?
最明顯的就是我們在整個流程中都看不到ActionForm對象了,而且Action雖然還是叫這個名字,但是
看起來已經跟Struts1中的Action完全不同了。
首先ActionForm被拋棄了,從前臺傳來的數據已經可以保存到任意POJO了。先存到ActionForm再復制
到Dto對象的日子已經是過去了。第二,這個POJO其實是Action對象中的一個成員變量。這在Struts1
中所有請求共享一個Action實例時是不可能的,現在Struts2會為每個請求都創建一個Action實例,所以
這樣做是行得通的。第三,雖然這樣可行,可是看起來好像Action作為MVC中的模型M既保存數據,又
包含了業務邏輯,這是不是不良的設計啊?其實仔細想想,這樣的設計很方便,我們已經得到了數據,
直接就可以去操作Service層了。Action的職責看似多了,其實并不多。
(2)前端Servlet怎么變成了Filter?
我們知道Struts1和Spring MVC都是通過前端Servlet來作為入口的,為什么Struts2要用Servlet的過濾器呢?
因為Struts2是基于Webwork核心的,與Struts1已經完全不同了。Webwork可以說降低了應用程序與J2EE
API的耦合,比如將ActionServlet改為Servlet的Filter,再比如對HttpServletRequest/Response的直接訪問,
又如任何POJO都能擔任ActionForm的角色,任何類不用實現Action接口就可以作為Action使用等等,
因此Struts2也繼承了這種優秀的非侵入式設計。
這點與Spring的設計思想有些相像。比如那些Ware接口,不關心的Bean完全不需要實現,盡量降低應用
程序代碼與框架的耦合。侵入性的確是框架設計時要考慮的一個重要因素。
(3)Filter、Action、Result間的粘合劑OGNL
下圖可以清晰明了地展示出OGNL是如何融入Struts2框架的。
在輸入頁面InputForm.html和返回頁面ResultPage.jsp使用Struts2標簽中訪問Action中的數據是如此方便,
OGNL使訪問ValueStack中保存的Action的屬性就像訪問ValueStack
自己的屬性一樣方便。
對OGNL的大量使用是Struts2的一大特色。包括前臺標簽傳值到Action,Result從Action中取值等都會大量
用到OGNL。而OGNL中大量用到了反射,我想也許這是Struts2性能不如Struts1的一個原因吧。畢竟獲得了
靈活而低耦合的架構的同時是要付出一定代價的。
(4)Interceptor的強是無敵的強
Struts2中另一個強大的特性就是Interceptor攔截器了。Struts2內建了大量的攔截器,攔截器使大量代碼可以
重復使用,自動化了之前我們所說的瑣屑的任務,從而使Struts2達到了高水平的關注分離。這真是AOP思想
在框架中應用的典范!Struts2中內建了很多有用的攔截器,稍后我們會專門來學習。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
