為什么 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)作。為了使用攔截器,您需要做三件事:
- 創(chuàng)建攔截器。
- 注冊(cè)攔截器。
- 聲明在何處攔截代碼。
??? 這看起來(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)用程序