向東博客

          非澹泊無(wú)以明志,非寧?kù)o無(wú)以致遠(yuǎn).
          posts - 12,  comments - 19,  trackbacks - 0

          為什么 Spring 這么了不起?

          ???? Spring 的創(chuàng)立者 Rod Johnson 以一種批判的眼光看待 Java? 企業(yè)軟件開(kāi)發(fā),并且提議很多企業(yè)難題都能夠通過(guò)戰(zhàn)略地使用 IOC 模式(也稱作依賴注入)來(lái)解決。當(dāng) Rod 和一個(gè)具有奉獻(xiàn)精神的開(kāi)放源碼開(kāi)發(fā)者團(tuán)隊(duì)將這個(gè)理論應(yīng)用于實(shí)踐時(shí),結(jié)果就產(chǎn)生了 Spring 框架。簡(jiǎn)言之,Spring 是一個(gè)輕型的容器,利用它可以使用一個(gè)外部 XML 配置文件方便地將對(duì)象連接在一起。每個(gè)對(duì)象都可以通過(guò)顯示一個(gè) JavaBean 屬性收到一個(gè)到依賴對(duì)象的引用,留給您的簡(jiǎn)單任務(wù)就只是在一個(gè) XML 配置文件中把它們連接好。

          IOC 和 Spring

          IOC 是一種使應(yīng)用程序邏輯外在化的設(shè)計(jì)模式,所以它是被注入而不是被寫(xiě)入客戶機(jī)代碼中。將 IOC 與接口編程應(yīng)用結(jié)合,就像 Spring 框架那樣,產(chǎn)生了一種架構(gòu),這種架構(gòu)能夠減少客戶機(jī)對(duì)特定實(shí)現(xiàn)邏輯的依賴。請(qǐng)參閱 參考資料 了解更多關(guān)于 IOC 和 Spring 的信息。

          ???? 依賴注入是一個(gè)強(qiáng)大的特性,但是 Spring 框架能夠提供更多特性。Spring 支持可插拔的事務(wù)管理器,可以給您的事務(wù)處理提供更廣泛的選擇范圍。它集成了領(lǐng)先的持久性框架,并且提供一個(gè)一致的異常層次結(jié)構(gòu)。Spring 還提供了一種使用面向方面代碼代替正常的面向?qū)ο蟠a的簡(jiǎn)單機(jī)制。

          ???? Spring AOP 允許您使用攔截器 在一個(gè)或多個(gè)執(zhí)行點(diǎn)上攔截應(yīng)用程序邏輯。加強(qiáng)應(yīng)用程序在攔截器中的日志記錄邏輯會(huì)產(chǎn)生一個(gè)更可讀的、實(shí)用的代碼基礎(chǔ),所以攔截器廣泛用于日志記錄。您很快就會(huì)看到,為了處理橫切關(guān)注點(diǎn),Spring AOP 發(fā)布了它自己的攔截器,您也可以編寫(xiě)您自己的攔截器。

          ?

          整合 Struts 和 Spring

          ??? 與 Struts 相似,Spring 可以作為一個(gè) MVC 實(shí)現(xiàn)。這兩種框架都具有自己的優(yōu)點(diǎn)和缺點(diǎn),盡管大部分人同意 Struts 在 MVC 方面仍然是最好的。很多開(kāi)發(fā)團(tuán)隊(duì)已經(jīng)學(xué)會(huì)在時(shí)間緊迫的時(shí)候利用 Struts 作為構(gòu)造高品質(zhì)軟件的基礎(chǔ)。Struts 具有如此大的推動(dòng)力,以至于開(kāi)發(fā)團(tuán)隊(duì)寧愿整合 Spring 框架的特性,而不愿意轉(zhuǎn)換成 Spring MVC。沒(méi)必要進(jìn)行轉(zhuǎn)換對(duì)您來(lái)說(shuō)是一個(gè)好消息。Spring 架構(gòu)允許您將 Struts 作為 Web 框架連接到基于 Spring 的業(yè)務(wù)和持久層。最后的結(jié)果就是現(xiàn)在一切條件都具備了。

          ???? 在接下來(lái)的小竅門中,您將會(huì)了解到三種將 Struts MVC 整合到 Spring 框架的方法。我將揭示每種方法的缺陷并且對(duì)比它們的優(yōu)點(diǎn)。 一旦您了解到所有三種方法的作用,我將會(huì)向您展示一個(gè)令人興奮的應(yīng)用程序,這個(gè)程序使用的是這三種方法中我最喜歡的一種。

          三個(gè)小竅門

          ???? 接下來(lái)的每種整合技術(shù)(或者竅門)都有自己的優(yōu)點(diǎn)和特點(diǎn)。我偏愛(ài)其中的一種,但是我知道這三種都能夠加深您對(duì) Struts 和 Spring 的理解。在處理各種不同情況的時(shí)候,這將給您提供一個(gè)廣闊的選擇范圍。方法如下:

          • 使用 Spring 的 ActionSupport 類整合 Structs
          • 使用 Spring 的 DelegatingRequestProcessor 覆蓋 Struts 的 RequestProcessor
          • 將 Struts Action 管理委托給 Spring 框架

          裝載應(yīng)用程序環(huán)境

          ??? 無(wú)論您使用哪種技術(shù),都需要使用 Spring 的 ContextLoaderPlugin 為 Struts 的 ActionServlet 裝載 Spring 應(yīng)用程序環(huán)境。就像添加任何其他插件一樣,簡(jiǎn)單地向您的 struts-config.xml 文件添加該插件,如下所示:

          < plug-in? className =
          ??"org.springframework.web.struts.ContextLoaderPlugIn"
          >
          ????
          < set-property? property =
          ??????"contextConfigLocation"
          ?value ="/WEB-INF/beans.xml" />
          ?
          </ plug-in >

          ???? 前面已經(jīng)提到過(guò),在 下載 部分,您能夠找到這三個(gè)完全可使用的例子的完整源代碼。每個(gè)例子都為一個(gè)書(shū)籍搜索應(yīng)用程序提供一種不同的 Struts 和 Spring 的整合方法。您可以在這里看到例子的要點(diǎn),但是您也可以下載應(yīng)用程序以查看所有的細(xì)節(jié)。

          竅門 1. 使用 Spring 的 ActionSupport

          ??? 手動(dòng)創(chuàng)建一個(gè) Spring 環(huán)境是一種整合 Struts 和 Spring 的最直觀的方式。為了使它變得更簡(jiǎn)單,Spring 提供了一些幫助。為了方便地獲得 Spring 環(huán)境,org.springframework.web.struts.ActionSupport 類提供了一個(gè) getWebApplicationContext() 方法。您所做的只是從 Spring 的 ActionSupport 而不是 Struts Action 類擴(kuò)展您的動(dòng)作,如清單 1 所示:


          清單 1. 使用 ActionSupport 整合 Struts

          ?1 package ?ca.nexcel.books.actions;
          ?2 import ?java.io.IOException;
          ?3 import ?javax.servlet.ServletException;
          ?4 import ?javax.servlet.http.HttpServletRequest;
          ?5 import ?javax.servlet.http.HttpServletResponse;
          ?6 import ?org.apache.struts.action.ActionError;
          ?7 import ?org.apache.struts.action.ActionErrors;
          ?8 import ?org.apache.struts.action.ActionForm;
          ?9 import ?org.apache.struts.action.ActionForward;
          10 import ?org.apache.struts.action.ActionMapping;
          11 import ?org.apache.struts.action.DynaActionForm;
          12 import ?org.springframework.context.ApplicationContext;
          13 import ?org.springframework.web.struts.ActionSupport;
          14 import ?ca.nexcel.books.beans.Book;
          15 import ?ca.nexcel.books.business.BookService;
          16 public ? class ?SearchSubmit? extends ?ActionSupport? {??? | ( 1 )
          17 ?? public ?ActionForward?execute(
          18 ????ActionMapping?mapping,
          19 ????ActionForm?form,
          20 ????HttpServletRequest?request,
          21 ????HttpServletResponse?response)
          22 ???? throws ?IOException,?ServletException? {
          23 ????DynaActionForm?searchForm? = ?(DynaActionForm)?form;
          24 ????String?isbn? = ?(String)?searchForm.get( " isbn " );
          25 ??
          26 ???? // the?old?fashion?way
          27 ???? // BookService?bookService?=?new?BookServiceImpl();
          28 ??
          29 ????ApplicationContext?ctx? = ?
          30 ??????getWebApplicationContext();???? | ( 2 )
          31 ????BookService?bookService? = ?
          32 ??????(BookService)?ctx.getBean( " bookService " );??? | ( 3 )
          33 ??Book?book? = ?bookService.read(isbn.trim());
          34 ???? if ?( null ? == ?book)? {
          35 ??????ActionErrors?errors? = ? new ?ActionErrors();
          36 ??????errors.add(ActionErrors.GLOBAL_ERROR, new ?ActionError
          37 ????????( " message.notfound " ));
          38 ??????saveErrors(request,?errors);
          39 ?????? return ?mapping.findForward( " failure " )?;
          40 ??}

          41 ????request.setAttribute( " book " ,?book);
          42 ???? return ?mapping.findForward( " success " );
          43 ??}

          44 }

          45

          ??? 讓我們快速思考一下這里到底發(fā)生了什么。在 (1) 處,我通過(guò)從 Spring 的 ActionSupport 類而不是 Struts 的 Action 類進(jìn)行擴(kuò)展,創(chuàng)建了一個(gè)新的 Action。在 (2) 處,我使用 getWebApplicationContext() 方法獲得一個(gè) ApplicationContext。為了獲得業(yè)務(wù)服務(wù),我使用在 (2) 處獲得的環(huán)境在 (3) 處查找一個(gè) Spring bean。

          ???? 這種技術(shù)很簡(jiǎn)單并且易于理解。不幸的是,它將 Struts 動(dòng)作與 Spring 框架耦合在一起。如果您想替換掉 Spring,那么您必須重寫(xiě)代碼。并且,由于 Struts 動(dòng)作不在 Spring 的控制之下,所以它不能獲得 Spring AOP 的優(yōu)勢(shì)。當(dāng)使用多重獨(dú)立的 Spring 環(huán)境時(shí),這種技術(shù)可能有用,但是在大多數(shù)情況下,這種方法不如另外兩種方法合適。

          竅門 2. 覆蓋 RequestProcessor

          ???? 將 Spring 從 Struts 動(dòng)作中分離是一個(gè)更巧妙的設(shè)計(jì)選擇。分離的一種方法是使用 org.springframework.web.struts.DelegatingRequestProcessor 類來(lái)覆蓋 Struts 的 RequestProcessor 處理程序,如清單 2 所示:


          清單 2. 通過(guò) Spring 的 DelegatingRequestProcessor 進(jìn)行整合

          ?1 <? xml?version="1.0"?encoding="ISO-8859-1"? ?>
          ?2 <! DOCTYPE?struts-config?PUBLIC
          ?3 ??????????"-//Apache?Software?Foundation//DTD?Struts?Configuration?1.1//EN"
          ?4 ??????????"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd" >
          ?5 < struts-config >
          ?6 ? < form-beans >
          ?7 ???? < form-bean? name ="searchForm" ?
          ?8 ??????type ="org.apache.struts.validator.DynaValidatorForm" >
          ?9 ??????????????? < form-property? name ="isbn" ????type ="java.lang.String" />
          10 ???? </ form-bean >
          11 ?? </ form-beans >
          12 ? < global-forwards? type ="org.apache.struts.action.ActionForward" >
          13 ????? < forward??? name ="welcome" ????????????????path ="/welcome.do" />
          14 ????? < forward??? name ="searchEntry" ????????????path ="/searchEntry.do" />
          15 ????? < forward??? name ="searchSubmit" ???????????path ="/searchSubmit.do" />
          16 ? </ global-forwards >
          17 ? < action-mappings >
          18 ???? < action???? path ="/welcome" ?forward ="/WEB-INF/pages/welcome.htm" />
          19 ???? < action???? path ="/searchEntry" ?forward ="/WEB-INF/pages/search.jsp" />
          20 ???? < action???? path ="/searchSubmit" ?
          21 ???????????????type ="ca.nexcel.books.actions.SearchSubmit"
          22 ???????????????input ="/searchEntry.do"
          23 ???????????????validate ="true"
          24 ???????????????name ="searchForm" >
          25 ?????????????? < forward? name ="success" ?path ="/WEB-INF/pages/detail.jsp" />
          26 ?????????????? < forward? name ="failure" ?path ="/WEB-INF/pages/search.jsp" />
          27 ???? </ action > ??
          28 ? </ action-mappings >
          29 ? < message-resources? parameter ="ApplicationResources" />
          30 ? < controller? processorClass ="org.springframework.web.struts.
          31 ???DelegatingRequestProcessor" /> ?|(1)
          32 ? < plug-in? className ="org.apache.struts.validator.ValidatorPlugIn" >
          33 ???? < set-property? property ="pathnames" ?
          34 ??????value ="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
          35 ? </ plug-in >
          36 ? < plug-in? className ="org.springframework.web.struts.ContextLoaderPlugIn" >
          37 ???? < set-property? property ="csntextConfigLocation" ?value ="/WEB-INF/beans.xml" />
          38 ? </ plug-in >
          39 </ struts-config >
          40


          ??? 我利用了 <controller> 標(biāo)記來(lái)用 DelegatingRequestProcessor 覆蓋默認(rèn)的 Struts RequestProcessor。下一步是在我的 Spring 配置文件中注冊(cè)該動(dòng)作,如清單 3 所示:


          清單 3. 在 Spring 配置文件中注冊(cè)一個(gè)動(dòng)作

          ?1 <? xml?version="1.0"?encoding="UTF-8" ?>
          ?2 <! DOCTYPE?beans?PUBLIC?"-//SPRING//DTD?BEAN//EN"?
          ?3 ??"http://www.springframework.org/dtd/spring-beans.dtd" >
          ?4 < beans >
          ?5 ?? < bean? id ="bookService" ?class ="ca.nexcel.books.business.BookServiceImpl" />
          ?6 ?? < bean? name ="/searchSubmit" ?
          ?7 ????class ="ca.nexcel.books.actions.SearchSubmit" > ?|(1)
          ?8 ????? < property? name ="bookService" >
          ?9 ???????? < ref? bean ="bookService" />
          10 ????? </ property >
          11 ?? </ bean >
          12 </ beans >
          13

          ?

          ??? 注意:在 (1) 處,我使用名稱屬性注冊(cè)了一個(gè) bean,以匹配 struts-config 動(dòng)作映射名稱。SearchSubmit 動(dòng)作揭示了一個(gè) JavaBean 屬性,允許 Spring 在運(yùn)行時(shí)填充屬性,如清單 4 所示:


          清單 4. 具有 JavaBean 屬性的 Struts 動(dòng)作

          ?1 package ?ca.nexcel.books.actions;
          ?2 import ?java.io.IOException;
          ?3 import ?javax.servlet.ServletException;
          ?4 import ?javax.servlet.http.HttpServletRequest;
          ?5 import ?javax.servlet.http.HttpServletResponse;
          ?6 import ?org.apache.struts.action.Action;
          ?7 import ?org.apache.struts.action.ActionError;
          ?8 import ?org.apache.struts.action.ActionErrors;
          ?9 import ?org.apache.struts.action.ActionForm;
          10 import ?org.apache.struts.action.ActionForward;
          11 import ?org.apache.struts.action.ActionMapping;
          12 import ?org.apache.struts.action.DynaActionForm;
          13 import ?ca.nexcel.books.beans.Book;
          14 import ?ca.nexcel.books.business.BookService;
          15 public ? class ?SearchSubmit? extends ?Action? {
          16 ?
          17 ?? private ?BookService?bookService;
          18 ?? public ?BookService?getBookService()? {
          19 ???? return ?bookService;
          20 ??}

          21 ?? public ? void ?setBookService(BookService?bookService)? {? | ?( 1 )
          22 ???? this .bookService? = ?bookService;?
          23 ??}
          ?
          24 ?? public ?ActionForward?execute(
          25 ????ActionMapping?mapping,
          26 ????ActionForm?form,
          27 ????HttpServletRequest?request,
          28 ????HttpServletResponse?response)
          29 ???? throws ?IOException,?ServletException? {
          30 ????DynaActionForm?searchForm? = ?(DynaActionForm)?form;
          31 ????String?isbn? = ?(String)?searchForm.get( " isbn " );
          32 ??
          33 ??Book?book? = ?getBookService().read(isbn.trim());?? | ( 2 )
          34 ???? if ?( null ? == ?book)? {
          35 ??????ActionErrors?errors? = ? new ?ActionErrors();
          36 ??????errors.add(ActionErrors.GLOBAL_ERROR, new ?ActionError( " message.notfound " ));
          37 ??????saveErrors(request,?errors);
          38 ?????? return ?mapping.findForward( " failure " )?;
          39 ??}

          40 ??????request.setAttribute( " book " ,?book);
          41 ?????? return ?mapping.findForward( " success " );
          42 ??}

          43 }

          44


          ??? 在清單 4 中,您可以了解到如何創(chuàng)建 Struts 動(dòng)作。在 (1) 處,我創(chuàng)建了一個(gè) JavaBean 屬性。DelegatingRequestProcessor自動(dòng)地配置這種屬性。這種設(shè)計(jì)使 Struts 動(dòng)作并不知道它正被 Spring 管理,并且使您能夠利用 Sping 的動(dòng)作管理框架的所有優(yōu)點(diǎn)。由于您的 Struts 動(dòng)作注意不到 Spring 的存在,所以您不需要重寫(xiě)您的 Struts 代碼就可以使用其他控制反轉(zhuǎn)容器來(lái)替換掉 Spring。

          ? DelegatingRequestProcessor 方法的確比第一種方法好,但是仍然存在一些問(wèn)題。如果您使用一個(gè)不同的 RequestProcessor,則需要手動(dòng)整合 Spring 的 DelegatingRequestProcessor。添加的代碼會(huì)造成維護(hù)的麻煩并且將來(lái)會(huì)降低您的應(yīng)用程序的靈活性。此外,還有過(guò)一些使用一系列命令來(lái)代替 Struts RequestProcessor 的傳聞。 這種改變將會(huì)對(duì)這種解決方法的使用壽命造成負(fù)面的影響。

          竅門 3. 將動(dòng)作管理委托給 Spring

          ?? 一個(gè)更好的解決方法是將 Strut 動(dòng)作管理委托給 Spring。您可以通過(guò)在 struts-config 動(dòng)作映射中注冊(cè)一個(gè)代理來(lái)實(shí)現(xiàn)。代理負(fù)責(zé)在 Spring 環(huán)境中查找 Struts 動(dòng)作。由于動(dòng)作在 Spring 的控制之下,所以它可以填充動(dòng)作的 JavaBean 屬性,并為應(yīng)用諸如 Spring 的 AOP 攔截器之類的特性帶來(lái)了可能。

          清單 5 中的 Action 類與清單 4 中的相同。但是 struts-config 有一些不同:


          清單 5. Spring 整合的委托方法

          ?1 <? xml?version="1.0"?encoding="ISO-8859-1"? ?>
          ?2 <! DOCTYPE?struts-config?PUBLIC
          ?3 ??????????"-//Apache?Software?Foundation//DTD?Struts?Configuration?1.1//EN"
          ?4 ??????????"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd" >
          ?5 < struts-config >
          ?6 ? < form-beans >
          ?7 ???? < form-bean? name ="searchForm" ?
          ?8 ??????type ="org.apache.struts.validator.DynaValidatorForm" >
          ?9 ??????????????? < form-property? name ="isbn" ????type ="java.lang.String" />
          10 ???? </ form-bean >
          11 ?? </ form-beans >
          12 ? < global-forwards? type ="org.apache.struts.action.ActionForward" >
          13 ????? < forward??? name ="welcome" ????????????????path ="/welcome.do" />
          14 ????? < forward??? name ="searchEntry" ????????????path ="/searchEntry.do" />
          15 ????? < forward??? name ="searchSubmit" ???????????path ="/searchSubmit.do" />
          16 ? </ global-forwards >
          17 ? < action-mappings >
          18 ???? < action???? path ="/welcome" ?forward ="/WEB-INF/pages/welcome.htm" />
          19 ???? < action???? path ="/searchEntry" ?forward ="/WEB-INF/pages/search.jsp" />
          20 ???? < action???? path ="/searchSubmit" ?
          21 ?????????????type ="org.springframework.web.struts.DelegatingActionProxy" ?|(1)
          22 ?????????????input ="/searchEntry.do"
          23 ?????????????validate ="true"
          24 ?????????????name ="searchForm" >
          25 ????????????? < forward? name ="success" ?path ="/WEB-INF/pages/detail.jsp" />
          26 ????????????? < forward? name ="failure" ?path ="/WEB-INF/pages/search.jsp" />
          27 ???? </ action > ??
          28 ? </ action-mappings >
          29 ? < message-resources? parameter ="ApplicationResources" />
          30 ? < plug-in? className ="org.apache.struts.validator.ValidatorPlugIn" >
          31 ???? < set-property?
          32 ???? property ="pathnames" ?
          33 ????value ="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
          34 ? </ plug-in >
          35 ? < plug-in?
          36 ???? className ="org.springframework.web.struts.ContextLoaderPlugIn" >
          37 ???? < set-property? property ="contextConfigLocation" ?value ="/WEB-INF/beans.xml" />
          38 ? </ plug-in >
          39 </ struts-config >
          40

          ??? 清單 5 是一個(gè)典型的 struts-config.xml 文件,只有一個(gè)小小的差別。它注冊(cè) Spring 代理類的名稱,而不是聲明動(dòng)作的類名,如(1)處所示。DelegatingActionProxy 類使用動(dòng)作映射名稱查找 Spring 環(huán)境中的動(dòng)作。這就是我們使用 ContextLoaderPlugIn 聲明的環(huán)境。

          ??? 將一個(gè) Struts 動(dòng)作注冊(cè)為一個(gè) Spring bean 是非常直觀的,如清單 6 所示。我利用動(dòng)作映射使用 <bean> 標(biāo)記的名稱屬性(在這個(gè)例子中是 "/searchSubmit")簡(jiǎn)單地創(chuàng)建了一個(gè) bean。這個(gè)動(dòng)作的 JavaBean 屬性像任何 Spring bean 一樣被填充:


          清單 6. 在 Spring 環(huán)境中注冊(cè)一個(gè) Struts 動(dòng)作

          ?1 <? xml?version="1.0"?encoding="UTF-8" ?>
          ?2 <! DOCTYPE?beans?PUBLIC?"-//SPRING//DTD?BEAN//EN"?
          ?3 ?"http://www.springframework.org/dtd/spring-beans.dtd" >
          ?4 < beans >
          ?5 ?? < bean? id ="bookService" ?class ="ca.nexcel.books.business.BookServiceImpl" />
          ?6 ?? < bean? name ="/searchSubmit" ???
          ?7 ????????class ="ca.nexcel.books.actions.SearchSubmit" >
          ?8 ????? < property? name ="bookService" >
          ?9 ???????? < ref? bean ="bookService" />
          10 ????? </ property >
          11 ?? </ bean >
          12 </ beans >
          13

          ?

          動(dòng)作委托的優(yōu)點(diǎn)

          ?? 動(dòng)作委托解決方法是這三種方法中最好的。Struts 動(dòng)作不了解 Spring,不對(duì)代碼作任何改變就可用于非 Spring 應(yīng)用程序中。RequestProcessor 的改變不會(huì)影響它,并且它可以利用 Spring AOP 特性的優(yōu)點(diǎn)。

          ??? 動(dòng)作委托的優(yōu)點(diǎn)不止如此。一旦讓 Spring 控制您的 Struts 動(dòng)作,您就可以使用 Spring 給動(dòng)作補(bǔ)充更強(qiáng)的活力。例如,沒(méi)有 Spring 的話,所有的 Struts 動(dòng)作都必須是線程安全的。如果您設(shè)置 <bean> 標(biāo)記的 singleton 屬性為“false”,那么不管用何種方法,您的應(yīng)用程序都將在每一個(gè)請(qǐng)求上有一個(gè)新生成的動(dòng)作對(duì)象。您可能不需要這種特性,但是把它放在您的工具箱中也很好。您也可以利用 Spring 的生命周期方法。例如,當(dāng)實(shí)例化 Struts 動(dòng)作時(shí),<bean> 標(biāo)記的 init-method 屬性被用于運(yùn)行一個(gè)方法。類似地,在從容器中刪除 bean 之前,destroy-method 屬性執(zhí)行一個(gè)方法。這些方法是管理昂貴對(duì)象的好辦法,它們以一種與 Servlet 生命周期相同的方式進(jìn)行管理。


          攔截 Struts

          ??? 前面提到過(guò),通過(guò)將 Struts 動(dòng)作委托給 Spring 框架而整合 Struts 和 Spring 的一個(gè)主要的優(yōu)點(diǎn)是:您可以將 Spring 的 AOP 攔截器應(yīng)用于您的 Struts 動(dòng)作。通過(guò)將 Spring 攔截器應(yīng)用于 Struts 動(dòng)作,您可以用最小的代價(jià)處理橫切關(guān)注點(diǎn)。

          ??? 雖然 Spring 提供很多內(nèi)置攔截器,但是我將向您展示如何創(chuàng)建自己的攔截器并把它應(yīng)用于一個(gè) Struts 動(dòng)作。為了使用攔截器,您需要做三件事:

          1. 創(chuàng)建攔截器。
          2. 注冊(cè)攔截器。
          3. 聲明在何處攔截代碼。

          ??? 這看起來(lái)非常簡(jiǎn)單的幾句話卻非常強(qiáng)大。例如,在清單 7 中,我為 Struts 動(dòng)作創(chuàng)建了一個(gè)日志記錄攔截器。 這個(gè)攔截器在每個(gè)方法調(diào)用之前打印一句話:


          清單 7. 一個(gè)簡(jiǎn)單的日志記錄攔截器

          1 package ?ca.nexcel.books.interceptors;
          2 import ?org.springframework.aop.MethodBeforeAdvice;
          3 import ?java.lang.reflect.Method;
          4 public ? class ?LoggingInterceptor? implements ?MethodBeforeAdvice? {
          5 ??? public ? void ?before(Method?method,?Object[]?objects,?Object?o)? throws ?Throwable? {
          6 ????????System.out.println( " logging?before! " );
          7 ????}

          8 }

          ??? 這個(gè)攔截器非常簡(jiǎn)單。before() 方法在攔截點(diǎn)中每個(gè)方法之前運(yùn)行。在本例中,它打印出一句話,其實(shí)它可以做您想做的任何事。下一步就是在 Spring 配置文件中注冊(cè)這個(gè)攔截器,如清單 8 所示:


          清單 8. 在 Spring 配置文件中注冊(cè)攔截器

          ?1 <! DOCTYPE?beans?PUBLIC? " -//SPRING//DTD?BEAN//EN " ?
          ?2 ?? " http://www.springframework.org/dtd/spring-beans.dtd " >
          ?3 < beans >
          ?4 ?? < bean?id = " bookService " ? class = " ca.nexcel.books.business.BookServiceImpl " />
          ?5 ?? < bean?name = " /searchSubmit " ?
          ?6 ???????? class = " ca.nexcel.books.actions.SearchSubmit " >
          ?7 ????? < property?name = " bookService " >
          ?8 ???????? < ref?bean = " bookService " />
          ?9 ????? </ property >
          10 ?? </ bean >
          11 ?? <!-- ??Interceptors? --> ?
          12 ?? < bean?name = " logger " ????
          13 ???? class = " ca.nexcel.books.interceptors.LoggingInterceptor " /> ? | ( 1 )
          14 ?? <!-- ?AutoProxies? -->
          15 ?? < bean?name = " loggingAutoProxy " ?
          16 ???????? class = " org.springframework.aop.framework.autoproxy.
          17 ??????????BeanNameAutoProxyCreator " >?|(2)
          18 ???? < property?name = " beanNames " >
          19 ?????????? < value >/ searchSubmit </ valuesgt;? | ( 3 )
          20 ???? </ property >
          21 ???? < property?name = " interceptorNames " >
          22 ???????? < list >
          23 ?????????? < value > logger </ value > ? | ( 4 )
          24 ???????? </ list >
          25 ???? </ property >
          26 ??? </ bean >
          27 </ beans >

          您可能已經(jīng)注意到了,清單 8 擴(kuò)展了 清單 6 中所示的應(yīng)用程序以包含一個(gè)攔截器。具體細(xì)節(jié)如下:

          • 在 (1) 處,我注冊(cè)了這個(gè)攔截器。
          • 在 (2) 處,我創(chuàng)建了一個(gè) bean 名稱自動(dòng)代理,它描述如何應(yīng)用攔截器。還有其他的方法定義攔截點(diǎn),但是這種方法常見(jiàn)而簡(jiǎn)便。
          • 在 (3) 處,我將 Struts 動(dòng)作注冊(cè)為將被攔截的 bean。如果您想要攔截其他的 Struts 動(dòng)作,則只需要在 "beanNames" 下面創(chuàng)建附加的 <value> 標(biāo)記。
          • 在 (4) 處,當(dāng)攔截發(fā)生時(shí),我執(zhí)行了在 (1) 處創(chuàng)建的攔截器 bean 的名稱。這里列出的所有攔截器都應(yīng)用于“beanNames”。

          ??? 就是這樣。就像這個(gè)例子所展示的,將您的 Struts 動(dòng)作置于 Spring 框架的控制之下,為處理您的 Struts 應(yīng)用程序提供了一系列全新的選擇。在本例中,使用動(dòng)作委托可以輕松地利用 Spring 攔截器提高 Struts 應(yīng)用程序中的日志記錄能力。

          結(jié)束語(yǔ)

          ??? 在本文中,您已經(jīng)學(xué)習(xí)了將 Struts 動(dòng)作整合到 Spring 框架中的三種竅門。使用 Spring 的 ActionSupport 來(lái)整合 Struts(第一種竅門中就是這樣做的)簡(jiǎn)單而快捷,但是會(huì)將 Struts 動(dòng)作與 Spring 框架耦合在一起。如果您需要將應(yīng)用程序移植到一個(gè)不同的框架,則需要重寫(xiě)代碼。第二種解決方法通過(guò)委托 RequestProcessor 巧妙地解開(kāi)代碼的耦合,但是它的可擴(kuò)展性不強(qiáng),并且當(dāng) Struts 的 RequestProcessor 變成一系列命令時(shí),這種方法就持續(xù)不了很長(zhǎng)時(shí)間。第三種方法是這三種方法中最好的:將 Struts 動(dòng)作委托給 Spring 框架可以使代碼解耦,從而使您可以在您的 Struts 應(yīng)用程序中利用 Spring 的特性(比如日志記錄攔截器)。

          三種 Struts-Spring 整合竅門中的每一種都被實(shí)現(xiàn)成一個(gè)完整可用的應(yīng)用程序

          posted on 2006-09-21 22:15 向東博客 閱讀(432) 評(píng)論(0)  編輯  收藏 所屬分類: 數(shù)據(jù)庫(kù) 、開(kāi)發(fā)框架

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


          網(wǎng)站導(dǎo)航:
           







          留言簿(3)

          我參與的團(tuán)隊(duì)

          隨筆分類

          在線文檔

          網(wǎng)站

          最新隨筆

          積分與排名

          • 積分 - 58213
          • 排名 - 895

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 广水市| 临沂市| 鸡西市| 花莲县| 新龙县| 淳化县| 石屏县| 建始县| 大悟县| 龙海市| 武义县| 文安县| 都安| 织金县| 聊城市| 交口县| 香港 | 方正县| 新化县| 山东省| 北京市| 常德市| 鹿泉市| 梧州市| 岫岩| 西城区| 长春市| 广德县| 黎平县| 禄丰县| 鄂托克前旗| 黑水县| 正定县| 屏东县| 宁夏| 林芝县| 眉山市| 隆回县| 阿拉善盟| 泗阳县| 文化|