|
本篇文章讓我們來(lái)詳細(xì)探討一下Struts2的配置文件的結(jié)構(gòu)、配置文件的各個(gè)節(jié)點(diǎn)和每個(gè)節(jié)點(diǎn)中元素的使用方式。
總攬Struts2的配置文件是以XML的形式出現(xiàn)的。不過(guò)它的XML的語(yǔ)義比較簡(jiǎn)單,下面是我抽取了位于struts2-core-2.0.14.jar內(nèi)部的struts-default.xml的片段:
在這個(gè)配置文件中,我們可以看到,Struts2的XML自身所支持的節(jié)點(diǎn)和子節(jié)點(diǎn)并不是很多,大致來(lái)說(shuō),這些節(jié)點(diǎn)可以分成基本配置定義和Runtime配置定義。 基本配置定義 基本配置定義,主要是針對(duì)在Struts2內(nèi)部所使用的各種元素的聲明。這些聲明往往規(guī)定了Struts2內(nèi)部的一些行為特征。 例如,配置文件中的<bean>節(jié)點(diǎn),被用于定義Struts2中所使用的接口和實(shí)現(xiàn)類(lèi),通過(guò)Struts2內(nèi)部實(shí)現(xiàn)的IoC,你就可以在不同的實(shí)現(xiàn)類(lèi)之間進(jìn)行切換。 再例如,配置文件中的<result-type>節(jié)點(diǎn)和<interceptor>節(jié)點(diǎn)。他們用于定義Struts2中所支持的所有的Result類(lèi)型和攔截器,這些定義和聲明,將在Runtime的配置定義中被引用。 我之所以把配置文件中的這些節(jié)點(diǎn)單獨(dú)列出來(lái),作為一個(gè)種類(lèi),是因?yàn)?strong style="FONT-WEIGHT: bold">這些節(jié)點(diǎn)是不可省略的,也是無(wú)法簡(jiǎn)化的。所以,如果我們?cè)噲D在Struts2中簡(jiǎn)化配置,我們就需要在Runtime配置定義中下功夫,而這些基本配置定義,我們可以認(rèn)為是Runtime配置定義的基礎(chǔ)。 Runtime配置定義 Runtime配置定義,主要指的的是對(duì)Struts2運(yùn)行過(guò)程中,具體的某個(gè)Action的行為的指定。這些指定主要通過(guò)<package>節(jié)點(diǎn)中的<action>節(jié)點(diǎn)來(lái)完成。 仔細(xì)翻閱<action>節(jié)點(diǎn),我們可以發(fā)現(xiàn),它是URL與Action之間溝通的橋梁,也就是說(shuō),它定義了URL與Action之間的對(duì)應(yīng)關(guān)系。同時(shí),它還指定了Action在執(zhí)行過(guò)程中的具體行為,包括Action執(zhí)行的時(shí)候使用什么樣的攔截器、Action執(zhí)行完畢后,轉(zhuǎn)向到什么樣的Result等等。 Runtime配置定義是可以簡(jiǎn)化的,Struts2中提供了很多種簡(jiǎn)化配置的方式,這個(gè)在之后的文章中會(huì)詳細(xì)提到。 模塊化管理配置文件一旦項(xiàng)目變得很大,項(xiàng)目中同時(shí)也并不采取什么簡(jiǎn)化配置的措施,那么在默認(rèn)情況下,配置文件就會(huì)變得很大而不易于維護(hù)。這個(gè)時(shí)候,對(duì)于配置文件的模塊化管理的需求就顯現(xiàn)出來(lái)。Struts2提供了兩種方式對(duì)配置文件進(jìn)行模塊化管理。
plugin機(jī)制 Struts2有plugin的機(jī)制,有關(guān)plugin的具體的知識(shí),請(qǐng)參考我的另外一篇專(zhuān)欄文章:《深入plugin》 —— http://www./wiki/struts2/1333-deep-into-plugin。在這里,我也就不詳細(xì)介紹了。 在每個(gè)plugin中,都會(huì)有一個(gè)叫做struts-plugin.xml的配置文件,這個(gè)配置文件的格式與struts-default.xml的格式是相同的。可以在其中做出任何的Struts2的定義和配置。我們知道,Struts2的配置文件的加載順序,是按照以下的順序來(lái): Struts2 Referece 寫(xiě)道
1. struts-default.xml (bundled in the Core JAR)
2. struts-plugin.xml (as many as can be found in other JARs) 3. struts.xml (provided by your application) 所以,struts-plugin.xml中的配置的效果實(shí)際上與struts-default.xml的效果是相同的。這樣,通過(guò)各種各樣不同的plugin,就等于將Struts2的配置,按照plugin的功能不同而分開(kāi)了。從而起到了配置文件模塊化管理的效果。 使用include節(jié)點(diǎn) plugin中的配置文件,實(shí)際上是位于classpath的JAR包中的,那么我們?cè)陧?xiàng)目中,如何對(duì)一個(gè)龐大的配置文件進(jìn)行拆分呢?在Struts2中,可以使用include節(jié)點(diǎn)對(duì)所有的Struts2配置文件進(jìn)行拆分和模塊化管理。例如:
其中,file所指定的文件是相對(duì)于classpath的相對(duì)目錄中的文件。而每個(gè)配置文件的格式與struts-default.xml的格式也是相同的。 通過(guò)include節(jié)點(diǎn),我們就可以對(duì)一個(gè)比較大的配置文件按照功能和模塊進(jìn)行拆分,這在一個(gè)大型的團(tuán)隊(duì)開(kāi)發(fā)中,是相當(dāng)有意義的。 簡(jiǎn)單的IoC在基本配置定義中,有兩個(gè)很常用的節(jié)點(diǎn):<bean>和<constant>。在系統(tǒng)啟動(dòng)的時(shí)候,Struts2會(huì)根據(jù)配置文件中這些<bean>和<constant>節(jié)點(diǎn)的定義進(jìn)行加載,并初始化成為Struts2的默認(rèn)行為。這種初始化的行為,非常類(lèi)似于Spring中的依賴(lài)注入(IoC),從而使得你不再需要擔(dān)心這些對(duì)象在運(yùn)行時(shí)的創(chuàng)建和銷(xiāo)毀,所有的工作都由Struts2內(nèi)部的機(jī)制實(shí)現(xiàn)。接下來(lái)我們就來(lái)看看Struts2是如何實(shí)現(xiàn)IoC的。
Struts2 Reference 寫(xiě)道
Internally, the framework uses its own dependency injection container that is very similar to Google Guice (both were originally developed by Bob Lee)
這是來(lái)自于Struts2的Reference對(duì)它自身的IoC的描述。如果熟悉Guice的朋友一定知道,Guice的實(shí)現(xiàn)使用了Annotation的方式進(jìn)行,而整個(gè)依賴(lài)注入的實(shí)現(xiàn),是通過(guò)一個(gè)內(nèi)部的容器類(lèi)進(jìn)行的。Struts2的依賴(lài)注入,與Guice的機(jī)制完全一致。根據(jù)注入的內(nèi)容的不同,Struts2的IoC可以對(duì)容器中的對(duì)象的依賴(lài)關(guān)系進(jìn)行管理,也可以注入一些靜態(tài)變量。 bean注入 對(duì)于bean的注入,對(duì)應(yīng)于XML中的bean的節(jié)點(diǎn)聲明。我把其中的機(jī)制分成了3個(gè)部分: 1. 容器中對(duì)象的聲明
這點(diǎn)沒(méi)什么好說(shuō)的,在struts.xml中,你可以為某個(gè)接口聲明它所對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)。 name屬性 你可以聲明多個(gè)實(shí)現(xiàn)類(lèi),使用name屬性進(jìn)行區(qū)分。在注入的時(shí)候,將使用這個(gè)屬性的值作為接口實(shí)現(xiàn)類(lèi)的選擇。 required屬性 你還可以通過(guò)required屬性,來(lái)指定是否在運(yùn)行時(shí)必不可少的注入。如果reqired被設(shè)置成false,那么當(dāng)不存在相應(yīng)的接口定義時(shí),注入將被忽略。 static屬性 在XML的定義中,還可以使用static屬性。如果static屬性被設(shè)置成true,那么注入將針對(duì)bean中的static方法和static屬性進(jìn)行。 2. 在代碼中使用Annotation進(jìn)行注入
在代碼中,使用@Inject這樣一個(gè)Annotation進(jìn)行對(duì)象依賴(lài)注入。在上面的例子中,我們可以看到,@Inject這個(gè)Annotation,可以作用在屬性上,也可以作用在方法上,甚至可以作用在方法的參數(shù)上。 在默認(rèn)情況下,如果@Inject不指定value,那么XML配置定義中的name="default"或者name=""的實(shí)現(xiàn)類(lèi)定義將被注入。 那么,在struts-default.xml中,Struts2到底選擇了那些實(shí)現(xiàn)類(lèi),作為Struts2或者XWork內(nèi)部接口的默認(rèn)實(shí)現(xiàn)類(lèi)呢?默認(rèn)情況下,struts-default.xml中定義的bean的name="struts"的將被作為默認(rèn)的接口實(shí)現(xiàn)類(lèi)被注入。這些默認(rèn)行為,是由org.apache.struts2.config.BeanSelectionProvider所決定的,有興趣的讀者可以參閱這個(gè)類(lèi)的源碼。 3. 內(nèi)部的Container機(jī)制完成一切背后工作 上面看到的,是現(xiàn)象。在內(nèi)部,Struts2通過(guò)一個(gè)Container來(lái)實(shí)現(xiàn)所有的注入機(jī)制。
在系統(tǒng)啟動(dòng)的時(shí)候,這個(gè)Container的實(shí)現(xiàn)類(lèi)就會(huì)工作,把XML中定義的內(nèi)容進(jìn)行注入。有興趣的讀者可以繼續(xù)探尋這個(gè)接口的實(shí)現(xiàn)類(lèi):com.opensymphony.xwork2.inject.ContainerImpl。 靜態(tài)變量(Constant)的注入 @Inject這個(gè)Annotation不僅能夠?qū)涌诘膶?shí)現(xiàn)類(lèi)進(jìn)行注入,也能夠?qū)o態(tài)變量進(jìn)行注入。 有關(guān)靜態(tài)變量的聲明和注入,在我的另外一篇專(zhuān)欄文章中已經(jīng)詳細(xì)闡述:《深入plugin》 —— http://www./wiki/struts2/1333-deep-into-plugin。在這里,我也就不詳細(xì)介紹了。 package節(jié)點(diǎn)詳解package節(jié)點(diǎn)是整個(gè)配置的核心部分。每個(gè)package,從語(yǔ)義上講,其實(shí)代表了每一個(gè)獨(dú)立的模塊。在這個(gè)模塊中,你可以定義隸屬于這個(gè)模塊的行為方式,而與其他的模塊沒(méi)有關(guān)系。所以,每個(gè)package都有獨(dú)立的interceptor、result-type和action的定義,絕大多數(shù)的Runtime配置定義都是通過(guò)package節(jié)點(diǎn)實(shí)現(xiàn)的。接下來(lái)我們就來(lái)詳細(xì)討論一下package中的屬性和子節(jié)點(diǎn)。
基本屬性 1. name name屬性為每個(gè)package設(shè)置一個(gè)唯一的標(biāo)識(shí),這個(gè)標(biāo)識(shí)在所有的package定義中不能重復(fù)。 2. abstract 標(biāo)識(shí)這個(gè)package的定義是一個(gè)抽象定義,也就是允許他僅包含聲明式的定義,而不需要在package定義中包含action的定義。 3. extends 通過(guò)使用extends,你可以指定本package繼承另外一個(gè)package的所有的配置。當(dāng)某個(gè)package繼承了另外一個(gè)package的所有配置,那么你就無(wú)需對(duì)父package中已經(jīng)聲明過(guò)的配置定義做再次的定義。 同時(shí),如果重復(fù)定義父package中已聲明過(guò)的配置定義,那么這些重復(fù)定義聲明將覆蓋父package中的相關(guān)定義。 4. namespace Struts2 Reference 寫(xiě)道
The namespace attribute subdivides action configurations into logical modules, each with its own identifying prefix. Namespaces avoid conflicts between action names. Each namespace can have its own "menu" or "help" action, each with its own implementation.
這段來(lái)自Struts2的Reference的引用,基本上闡明了namespace的作用:對(duì)于action配置進(jìn)行邏輯劃分。 如果我們不為package節(jié)點(diǎn)指定namespace,Struts2默認(rèn)使用一個(gè)空字符串作為默認(rèn)的namespace。當(dāng)然,也可以使用"/"等字符串來(lái)表示namespace。 Struts2在根據(jù)URL進(jìn)行尋址的時(shí)候,使用以下的步驟: 1) 根據(jù)URL進(jìn)行Namespace和ActionName的計(jì)算 2) 根據(jù)計(jì)算的得到的Namespace和ActionName查找package節(jié)點(diǎn)中相應(yīng)配置 3) 如果查找失敗,則查找Namespace為空,ActionName為整個(gè)URL的配置 有關(guān)上述3點(diǎn)的詳細(xì)信息,請(qǐng)參考Struts2的Reference:http://struts./2.0.14/docs/namespace-configuration.html result-types節(jié)點(diǎn) 在result-types節(jié)點(diǎn)中,我們可以聲明在本package中所支持的Result類(lèi)型。這些Result類(lèi)型,將在action節(jié)點(diǎn)中被引用到。 interceptors節(jié)點(diǎn) 在interceptors節(jié)點(diǎn)中有兩類(lèi)節(jié)點(diǎn):<interceptor>和<interceptor-stack>。這兩個(gè)節(jié)點(diǎn)都用于聲明攔截器。前者的作用,是真正定義一個(gè)攔截器。而后者則通過(guò)引用已經(jīng)定義的攔截器,指定他們的執(zhí)行順序。 當(dāng)我們?cè)谠噲D在A(yíng)ction中引用攔截器時(shí),我們實(shí)際上是為某個(gè)Action指定需要執(zhí)行哪些攔截器,并且為這些攔截器指定執(zhí)行順序。所以Action所引用的,是某個(gè)<interceptor-stack>中的定義。 缺省配置指向 為了簡(jiǎn)化配置,我們可以在package節(jié)點(diǎn)中指定本package內(nèi)的缺省配置指向。這可以通過(guò)<default-interceptor-ref>、<default-action-ref>、<global-results>等子節(jié)點(diǎn)來(lái)完成。 action節(jié)點(diǎn) action節(jié)點(diǎn)是所有的Runtime配置的核心內(nèi)容。它的主要作用就是指定URL與Action之間的映射關(guān)系。同時(shí),在action節(jié)點(diǎn)中你也可以指定action執(zhí)行時(shí)的相關(guān)配置,例如action所引用的interceptor等。 參考文檔上面所有的內(nèi)容,實(shí)際上我只是做了一些簡(jiǎn)單的概括和歸納,至于每個(gè)節(jié)點(diǎn)語(yǔ)義和每個(gè)節(jié)點(diǎn)中具體屬性的使用,我認(rèn)為還是需要參考Struts2的Reference,因?yàn)镽eference的講解比任何教程都來(lái)的詳細(xì)和正確,所以希望大家在了解了這些配置的基本分類(lèi)之后,重新閱讀Struts2的Reference的相關(guān)章節(jié),從而更加深刻的理解Struts2配置文件的方方面面:http://struts./2.0.14/docs/configuration-elements.html
3 樓 downpour 2009-01-19 12:49 引用to kyo100900:
我在實(shí)際開(kāi)發(fā)中,會(huì)根據(jù)實(shí)際情況編寫(xiě)一個(gè)相對(duì)全的interceptor-stack,作為默認(rèn)的攔截器指向。除非某個(gè)action的攔截器行為非常不同,否則我不會(huì)指定額外的interceptor-stack。 在Struts2的官方文檔中,有一篇有關(guān)Performance Tuning的文章:http://struts./2.0.14/docs/performance-tuning.html。在這篇文章中,提到了一個(gè)方面: Struts2 Reference 寫(xiě)道
Do not use interceptors you do not need.
不過(guò)從整個(gè)Struts2的執(zhí)行過(guò)程來(lái)看,多執(zhí)行幾個(gè)interceptor,對(duì)Struts2本身的性能影響并不是很大,僅僅是ActionInvocation中多執(zhí)行幾句代碼而已。這點(diǎn)代碼的執(zhí)行速度幾乎是可以忽略不計(jì)的。如果是你自己寫(xiě)的Interceptor,那么你還可以在你的Interceptor中做一定的邏輯判斷來(lái)避免無(wú)用代碼的執(zhí)行。 所以你所說(shuō)的2種方法我認(rèn)為都可以,根據(jù)具體的項(xiàng)目情況和個(gè)人喜好而定吧。 2 樓 kyo100900 2009-01-19 12:32 引用想問(wèn)downpour一個(gè)實(shí)踐問(wèn)題:
你在開(kāi)發(fā)的時(shí)候,會(huì)將各種 interceptor-stack 區(qū)分開(kāi)嗎? 就像下面
用的時(shí)候,具體的在<action />節(jié)點(diǎn)中指定。 或者就用那個(gè)大而全的默認(rèn) <interceptor-stack name="defaultStack"> 呢? 這個(gè)問(wèn)題圈子里面討論過(guò),我目前用的是后者,可能是項(xiàng)目不算特別復(fù)雜,沒(méi)有遇到所謂的struts性能問(wèn)題, 你有什么看法呢? |
|
|