高手支招 Java經(jīng)驗(yàn)分享(十)
這篇是筆者Java學(xué)習(xí)經(jīng)驗(yàn)分享的第十篇,這次準(zhǔn)備繼續(xù)上次的話題先講講Struts-2。首先簡(jiǎn)短回顧一段歷史:隨著時(shí)間的推移,Web應(yīng)用框架經(jīng)常變化的需求,產(chǎn)生了幾個(gè)下一代Struts的解決方案。其中的Struts Ti 繼續(xù)堅(jiān)持 MVC模式的基礎(chǔ)上改進(jìn),繼續(xù)Struts的成功經(jīng)驗(yàn)WebWork項(xiàng)目是在2002年3月發(fā)布的,它對(duì)Struts式框架進(jìn)行了革命性改進(jìn),引進(jìn)了不少新的思想,概念和功能,但和原Struts代碼并不兼容。WebWork是一個(gè)成熟的框架,經(jīng)過(guò)了好幾次重大的改進(jìn)與發(fā)布。在2005年12月,WebWork與Struts Ti決定合拼,再此同時(shí),Struts Ti 改名為 Struts Action Framework 2.0,成為Struts真正的下一代。
看看Struts-2的處理流程:
1) Browser產(chǎn)生一個(gè)請(qǐng)求并提交框架來(lái)處理:根據(jù)配置決定使用哪些攔截器、action類和結(jié)果等。
2) 請(qǐng)求經(jīng)過(guò)一系列攔截器:根據(jù)請(qǐng)求的級(jí)別不同攔截器做不同的處理。這和Struts-1的RequestProcessor類很相似。
3) 調(diào)用Action: 產(chǎn)生一個(gè)新的action實(shí)例,調(diào)用業(yè)務(wù)邏輯方法。
4) 調(diào)用產(chǎn)生結(jié)果:匹配result class并調(diào)用產(chǎn)生實(shí)例。
5) 請(qǐng)求再次經(jīng)過(guò)一系列攔截器返回:過(guò)程也可配置減少攔截器數(shù)量
6) 請(qǐng)求返回用戶:從control返回servlet,生成Html。
這里很明顯的一點(diǎn)是不存在FormBean的作用域封裝,直接可以從Action中取得數(shù)據(jù)。 這里有一個(gè)Strut-2配置的web.xml文件:
- <filter>
- <filter-name> controller </filter-name>
- <filter-class> org.apache.struts.action2.dispatcher.FilterDispatcher </filter-class>
- </filter>
- <filter-mapping>
- <filter-name> cotroller </filter-name>
- <url-pattern> /* </url-pattern>
- </filter-mapping>
注意到以往的servlet變成了filter,ActionServlet變成了FilterDispatcher,*.do變成了/*。filter配置定義了名稱(供關(guān)聯(lián))和filter的類。filter mapping讓URI匹配成功的的請(qǐng)求調(diào)用該filter。默認(rèn)情況下,擴(kuò)展名為 ".action "。這個(gè)是在default.properties文件里的 "struts.action.extension "屬性定義的。
default.properties是屬性定義文件,通過(guò)在項(xiàng)目classpath路徑中包含一個(gè)名為“struts.properties”的文件來(lái)設(shè)置不同的屬性值。而Struts-2的默認(rèn)配置文件名為struts.xml。由于1和2的action擴(kuò)展名分別為.do和.action,所以很方便能共存。我們?cè)賮?lái)看一個(gè)Struts-2的action代碼:
- public class MyAction {
- public String execute() throws Exception {
- //do the work
- return "success ";
- }
- }
很明顯的區(qū)別是不用再繼承任何類和接口,返回的只是一個(gè)String,無(wú)參數(shù)。實(shí)際上在Struts-2中任何返回String的無(wú)參數(shù)方法都可以通過(guò)配置來(lái)調(diào)用action。所有的參數(shù)從哪里來(lái)獲得呢?答案就是Inversion of Control技術(shù)(控制反轉(zhuǎn))。筆者盡量以最通俗的方式來(lái)解釋,我們先試圖讓這個(gè)Action獲得reuqest對(duì)象,這樣可以提取頁(yè)面提交的任何參數(shù)。那么我們把request設(shè)為一個(gè)成員變量,然后需要一個(gè)對(duì)它的set方法。由于大部分的action都需要這么做,我們把這個(gè)set方法作為接口來(lái)實(shí)現(xiàn)。
- public interface ServletRequestAware {
- public void setServletRequest(HttpServletRequest request);
- }
- public class MyAction implements ServletRequestAware {
- private HttpServletRequest request;
- public void setServletRequest(HttpServletRequest request) {
- this.request = request;
- }
- public String execute() throws Exception {
- // do the work directly using the request
- return Action.SUCCESS;
- }
- }
那么誰(shuí)來(lái)調(diào)用這個(gè)set方法呢?也就是說(shuō)誰(shuí)來(lái)控制這個(gè)action的行為,以往我們都是自己在適當(dāng)?shù)牡胤綄?xiě)上一句action.setServletRequest(…),也就是控制權(quán)在程序員這邊。然而控制反轉(zhuǎn)的思想是在哪里調(diào)用交給正在運(yùn)行的容器來(lái)決定,只要利用Java反射機(jī)制來(lái)獲得Method對(duì)象然后調(diào)用它的invoke方法傳入?yún)?shù)就能做到,這樣控制權(quán)就從程序員這邊轉(zhuǎn)移到了容器那邊。程序員可以減輕很多繁瑣的工作更多的關(guān)注業(yè)務(wù)邏輯。Request可以這樣注入到action中,其他任何對(duì)象也都可以。為了保證action的成員變量線程安全,Struts-2的action不是單例的,每一個(gè)新的請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的action實(shí)例。
那么有人會(huì)問(wèn),到底誰(shuí)來(lái)做這個(gè)對(duì)象的注入工作呢?答案就是攔截器。攔截器又是什么東西?筆者再來(lái)盡量通俗的解釋攔截器的概念。大家要理解攔截器的話,首先一定要理解GOF23種設(shè)計(jì)模式中的Proxy模式。
A對(duì)象要調(diào)用f(),它希望代理給B來(lái)做,那么B就要獲得A對(duì)象的引用,然后在B的f()中通過(guò)A對(duì)象引用調(diào)用A對(duì)象的f()方法,最終達(dá)到A的f()被調(diào)用的目的。有沒(méi)有人會(huì)覺(jué)得這樣很麻煩,為什么明明只要A.f()就可以完成的一定要封裝到B的f()方法中去?有哪些好處呢?
1) 這里我們只有一個(gè)A,當(dāng)我們有很多個(gè)A的時(shí)候,只需要監(jiān)視B一個(gè)對(duì)象的f()方法就可以從全局上控制所有被調(diào)用的f()方法。
2) 另外,既然代理人B能獲得A對(duì)象的引用,那么B可以決定在真正調(diào)A對(duì)象的f()方法之前可以做哪些前置工作,調(diào)完返回前可有做哪些后置工作。
講到這里,大家看出來(lái)一點(diǎn)攔截器的概念了么?它攔截下一調(diào)f()方法的請(qǐng)求,然后統(tǒng)一的做處理(處理每個(gè)的方式還可以不同,解析A對(duì)象就可以辨別),處理完畢再放行。這樣像不像對(duì)流動(dòng)的河水橫切了一刀,對(duì)所有想通過(guò)的水分子進(jìn)行搜身,然后再放行?這也就是AOP(Aspect of Programming面向切面編程)的思想。
Anyway,Struts-2只是利用了AOP和IoC技術(shù)來(lái)減輕action和框架的耦合關(guān)系,力圖到***程度重用action的目的。在這樣的技術(shù)促動(dòng)下,Struts-2的action成了一個(gè)簡(jiǎn)單被框架使用的POJO(Plain Old Java Object)罷了。實(shí)事上AOP和IoC的思想已經(jīng)遍布新出來(lái)的每一個(gè)框架上,他們并不是多么新的技術(shù),利用的也都是JDK早已可以最到的事情,它們代表的是更加面向接口編程,提高重用,增加擴(kuò)展性的一種思想。Struts-2只是部分的使用這兩種思想來(lái)設(shè)計(jì)完成的,另外一個(gè)最近很火的框架Spring,更大程度上代表了這兩種設(shè)計(jì)思想,筆者將于下一篇來(lái)進(jìn)一步探討Spring的結(jié)構(gòu)。
附言: 關(guān)于Struts-2筆者也沒(méi)真正怎么用過(guò),這里是看了網(wǎng)上一些前輩的帖子之后寫(xiě)下自己的學(xué)習(xí)體驗(yàn),不足之處請(qǐng)見(jiàn)諒!
【編輯推薦】