2005年11月9日
Web應(yīng)用是Web服務(wù)的一種動(dòng)態(tài)擴(kuò)展。Web應(yīng)用可分為兩類:
- ?面向表示的Web應(yīng)用。在響應(yīng)請(qǐng)求時(shí),面向表示的Web應(yīng)用產(chǎn)生動(dòng)態(tài)的Web頁面,這種頁面包含了各種不同的標(biāo)記語言(如HTML,
XML, 等等)。
- 面向服務(wù)的Web應(yīng)用。面向服務(wù)的Web應(yīng)用實(shí)現(xiàn)細(xì)粒度Web服務(wù)的端點(diǎn)。面向服務(wù)Web應(yīng)用通常為面向表示應(yīng)用所調(diào)用。
在Java2平臺(tái)上,Web組件為Web
服務(wù)器提供了動(dòng)態(tài)擴(kuò)展能力。Web組件可以是Java
Servlets或者JSP頁面。Servlets是Java編程語言中用于動(dòng)態(tài)地處理請(qǐng)求和建立響應(yīng)的一種類。JSP頁面是基于文本的文檔,它像
servlets一樣執(zhí)行,但是允許使用更自然的方法來創(chuàng)建靜態(tài)內(nèi)容。盡管servlet和JSP頁面可以交替地使用,但是它們各有千秋。
Servlets最適合于面向服務(wù)的Web應(yīng)用,同時(shí)還擅長于管理面向表示的Web服務(wù)的控制功能,例如發(fā)送請(qǐng)求和處理非原文的數(shù)據(jù)。而JSP頁面則更適
合于產(chǎn)生基于文本的標(biāo)記,例如:HTML、SVG、WML以及XML等。
Web組件以一個(gè)名為Web容器
的運(yùn)行時(shí)平臺(tái)中的服務(wù)作為支撐。在Java Web服務(wù)開發(fā)包(Java Web Services Developer
Pack, Java WSDP)中的Web組件在Tomcat Web容器內(nèi)運(yùn)行。Web容器提供了一些服務(wù),例如請(qǐng)求發(fā)送、安全、并發(fā)以及生命周期管理。它還使得Web組件可以訪問多種API,
例如命名、事務(wù)處理以及e-mail等方面的API。
本章里描述了Web應(yīng)用的組織、配置以及安裝和部署過程。第11章和第12章中講述如何開發(fā)面向服務(wù)的Web應(yīng)用的Web組件。第14章和第15章講述如何開發(fā)面向表示W(wǎng)eb的應(yīng)用的Web組件。JSP技術(shù)的許多特征是由Java
Servlet技術(shù)決定的,因此即使你不打算編寫servlet,也應(yīng)該熟悉這方面的知識(shí)。
大多數(shù)Web應(yīng)用都使用HTTP協(xié)議,而且對(duì)HTTP的支持也正是Web組件的一個(gè)主要方面。對(duì)于HTTP協(xié)議特征的簡要總結(jié),參見HTTP概述。
Web應(yīng)用的生命周期
Web應(yīng)用由Web組件、靜態(tài)資源文件(如圖像)、幫助類和庫組成。Java
WSDP提供許多支持服務(wù),用于增強(qiáng)Web組件的性能并使得它們更易于開發(fā)。不過,由于要充分考慮這些支持服務(wù),所以Web應(yīng)用在創(chuàng)建和運(yùn)行過程上與傳統(tǒng)的stand-alone式的Java類有所不同。
在Web應(yīng)用被部署以后,就可以對(duì)其行為的某些方面進(jìn)行配置。配置信息通過Web應(yīng)用部署描述文件來維護(hù),該文件是一種XML格式的文本文件。部署描述文件必須遵從Java
Servlet規(guī)范中描述的模式。
創(chuàng)建、部署和執(zhí)行Web應(yīng)用的過程可以總結(jié)為以下幾步:
1.開發(fā)Web組件代碼(可能還包括部署描述文件)。
2.建立Web應(yīng)用組件連同所有靜態(tài)資源(例如圖像)和組件要引用到的幫助類。
3.將應(yīng)用安裝或部署到Web容器中。
4.訪問指向該Web應(yīng)用的URL。
開
發(fā)Web組件代碼這方面的知識(shí)將在以后的章節(jié)中講述。接下來的幾節(jié)將對(duì)步驟2到步驟4作出詳細(xì)的講解,并給出一個(gè)Hello,World式的面向表示的應(yīng)
用的例子。該應(yīng)用允許用戶輸入名字到HTML表單中(見圖4-1),并且在名字提交之后顯示一條問候信息(見圖4―2)。
圖4-1 問候表單
圖4-2
響應(yīng)
這個(gè)Hello應(yīng)用包含了兩個(gè)Web組件,用于產(chǎn)生問候信息和響應(yīng)。在本指南中,該應(yīng)用有兩個(gè)版本:一個(gè)是servlet版,名為Hello1,它的組件通過兩個(gè)servlet類(GreetingServlet.java和ResponseServlet.java)來實(shí)現(xiàn)。另一個(gè)是JSP版,名為Hello2,它的組件通過兩個(gè)JSP頁面(greeting.jsp 和 response.jsp)來實(shí)現(xiàn)。這兩個(gè)版本的例子展示了一個(gè)包含Web組件的應(yīng)用在大包、部署和運(yùn)行時(shí)所涉及到的任務(wù)。如果你是在線瀏覽本指南,請(qǐng)務(wù)必下載本指南的捆綁包,以獲得這個(gè)示例的源代碼。
Web應(yīng)用歸檔文件
如果要發(fā)布一個(gè)Web應(yīng)用,你可以將其打包到一個(gè)Web應(yīng)用歸檔文件(Web
application archive,WAR)中,WAR與JAR類似,都是用作Java類庫的包。除了應(yīng)用的Web組件外,Web應(yīng)用的歸檔文件還包含其他的一些文件,包括:
·?? 服務(wù)器端的實(shí)用工具類(如數(shù)據(jù)庫bean、購物車等等)。這些類通常與JavaBeans組件的結(jié)構(gòu)一致。
·?? 靜態(tài)Web表示內(nèi)容(如HTML,圖像和聲音文件等)
·?? 客戶端類(applet和實(shí)用工具類)
Web組件和靜態(tài)Web內(nèi)容文件叫做Web資源。
Web應(yīng)用的運(yùn)行可以通過一個(gè)WAR文件,或者通過一個(gè)同為WAR格式的解包目錄。
WAR目錄結(jié)構(gòu)
WAR的頂級(jí)目錄是該應(yīng)用的文檔根目錄。這個(gè)文檔根目錄下存放著JSP頁面、客戶端類和歸檔文件,以及靜態(tài)Web資源。
文檔根目錄下含有一個(gè)名為WEB-INF的子目錄,其中包含了以下文件和目錄:
·?? web.xml
—— Web應(yīng)用的部署描述文件。
·?? 標(biāo)簽庫描述文件。
·?? classes
—— 一個(gè)子目錄,包含了服務(wù)器端類:servlets,實(shí)用工具類和JavaBeans組件。
·?? lib
—— 一個(gè)子目錄,包含了庫(標(biāo)簽庫和所有作為服務(wù)器端類的實(shí)用工具類)
還可以創(chuàng)建應(yīng)用專用(application-specific)的子目錄(即包目錄),可以在文檔根目錄下創(chuàng)建,或者在WEB-INF/classes
目錄下創(chuàng)建。
指南示例的目錄結(jié)構(gòu)
為了便于迭代開發(fā)并且將Web應(yīng)用的源代碼與已編譯的文件分開,實(shí)例的源代碼存儲(chǔ)在每個(gè)應(yīng)用目錄mywebapp
下,其結(jié)構(gòu)如下:
·?? build.xml
—— Ant生成文件
·?? context.xml
——可選應(yīng)用配置文件
·?? src
—— servler和Javabeans組件的Java源代碼。
·?? web
—— JSP頁面和HTML頁面、圖像。
隨示例一起發(fā)布的Ant
build文件(build.xml)中包含了一些目標(biāo) (target),用以在mywebapp
的build
子目錄中創(chuàng)建解包的WAR結(jié)構(gòu),將文件拷貝和編譯到那個(gè)目錄中,并且通過專門的Ant任務(wù)調(diào)用manager
命令,來安裝、重新裝載、移除、部署和解部署應(yīng)用。該指南示例的Ant目標(biāo)是:
·?? prepare
(準(zhǔn)備) —— 創(chuàng)建build目錄和WAR子目錄。
·?? build
(編譯) —— 編譯和拷貝mywebapp
Web應(yīng)用文件到build目錄下。
·?? install
(安裝)—— 使用Ant install
任務(wù)通知Tomcat安裝應(yīng)用(見安裝Web應(yīng)用)。
·?? reload
(重新裝載)—— 使用Ant reload
任務(wù)通知Tomcat重新裝載應(yīng)用(見更新Web應(yīng)用)。
·?? deploy
(部署) —— 使用Ant deploy任務(wù)通知Tomcat部署應(yīng)用(見部署Web應(yīng)用)。
·?? undeploy
(解除部署)——使用Ant undeploy任務(wù)通知Tomcat解除部署應(yīng)用(見解除部署Web應(yīng)用)
·?? remove
(移除) —— 使用 Ant remove
任務(wù)通知Tomcat移除應(yīng)用(見移除Web應(yīng)用)
創(chuàng)建WAR
手工的創(chuàng)建WAR文件有兩種方法:
·?? 使用隨J2SE SDK一起發(fā)布的JAR工具。只需簡單地在指南示例的build目錄下執(zhí)行如下命令:
jar cvf mywebapp
.war
.
·?? 使用Ant war
任務(wù)
這兩種方法都要求有創(chuàng)建好的Web應(yīng)用部署描述文件。
配置Web應(yīng)用
Web
應(yīng)用的配置是通過包含在Web應(yīng)用部署描述文件中的元素的設(shè)置來實(shí)現(xiàn)的。你可以使用文本編輯器來手工創(chuàng)建這些描述文件。接下來的章節(jié)將對(duì)你想配置的Web
應(yīng)用特征作一個(gè)簡要的介紹。其中,許多的安全參數(shù)都可以在配置時(shí)指定,這些內(nèi)容在第18章可以看到。如果你想得到這些特征的完整列表和描述,參見Java
Servlet規(guī)范。
在接下來的幾節(jié)中,將給出一些示例來演示Hello,World應(yīng)用的配置過程。如果Hello,World沒有使用指定的配置特征,那么本節(jié)將給出其他的示例來展示部署描述文件的元素并描述指定這種特征的一般過程。
注
意:描述符元素必須在部署描述文件中按照下列順序出現(xiàn):icon,display,description,distributable,context
-param,filter,filter-mapping,listener,servlet,servlet-mapping,session-config,mime-mapping,welcome-file-list,error-page,taglib,resource-env-ref,resource-ref,security-contraint,login-config,seurity-role,env-entry.
序言
既然部署描述文件是一種XML文檔,它就需要一個(gè)序言。Web應(yīng)用的部署描述文件的序言如下所示:
別名路徑
當(dāng)Tomcat收到一個(gè)請(qǐng)求時(shí),它必須決定使用哪個(gè)Web組件來處理請(qǐng)求。這一步是通過將包含在請(qǐng)求中的URL路徑映像到一個(gè)Web組件來實(shí)現(xiàn)的。URL路徑包含上下文根目錄(參見Installing
Web Application,http://java.sun.com/webservices/docs/1.1/tutorial/doc/WebApp5.html#wp75667)和一個(gè)別名路徑。
http://<host>:8080/context_root
/alias_path
http://<host>:8080/context_root
/alias_path
?
在servlet
可以被訪問前,Web容器必須最少有一個(gè)該組件的別名路徑。別名路徑必須以一個(gè)“/”開始,以一個(gè)字符串或者一個(gè)帶擴(kuò)展名的通配符(例如:*.jsp)結(jié)
束。既然Web容器自動(dòng)地映像到以*.jsp結(jié)束的別名路徑,你無需為JSP頁面指定別名路徑,除非你想通過一個(gè)名稱,而不是其文件名來引用JSP頁面。
在更新Web應(yīng)用中討論的實(shí)例中,問候頁面有一個(gè)別名response.jsp,但它仍然是通過其文件名來引用的。
在Web
部署描述文件中設(shè)置servlet版的Hello應(yīng)用的映像,必須添加下列servlet和servlet-mapping元素到Web應(yīng)用部署描述文件
中。為了定義JSP頁面的別名,必須替換在servlet元素中的servlet-class子元素和jsp-file子元素。
??greeting
??greeting
??no description
??GreetingServlet
??response
??response
??no description
??ResponseServlet
??greeting
??/greeting
??response
??/response
上下文和初始化參數(shù)
同
一個(gè)WAR中的各Web組件共享一個(gè)表示它們的應(yīng)用上下文的對(duì)象(見訪問Web上下文)。你可以傳遞參數(shù)到上下文或者Web組件。要實(shí)現(xiàn)這一點(diǎn),你必須添
加一個(gè)context-param或init-param元素到Web應(yīng)用部署描述文件中。context-param是頂級(jí)web-app元素的子元
素。init-param是servlet元素的子元素。下面的元素用于聲明一個(gè)上下文參數(shù),該參數(shù)設(shè)置在第17章中討論的示例的資源束:
??
????
??????javax.servlet.jsp.jstl.fmt.localizationContext
????
????messages.BookstoreMessages
??
??...
事件監(jiān)聽器
要添加事件監(jiān)聽器類,必須添加一個(gè)listener元素到Web應(yīng)用部署描述文件中。下面的元素描述了在第14章和第17章用到的監(jiān)聽器類)。
??listeners.ContextListener
過濾器映像
Web
容器使用過濾器映像聲明來決定應(yīng)用于某個(gè)請(qǐng)求的過濾器,并且決定這些過濾器的順序。正如在別名路徑中描述的那樣,該容器將請(qǐng)求URL與一個(gè)servlet
相匹配。要決定引用哪個(gè)過濾器,容器通過servlet名或者URL模式來匹配過濾器映像聲明。過濾器被調(diào)用的順序就是過濾器映像聲明在過濾器映像列表中
出現(xiàn)的順序,過濾器映像聲明將請(qǐng)求URI與一個(gè)servlet匹配起來。
要指定過濾器映像,必須添加一個(gè)filter和filter-mapping元素到Web應(yīng)用部署描述文件中。下面的元素用于聲明有序的過濾器,并將其映像到在第14章討論過的Receipt
servlet:
??OrderFilter
??filters.OrderFilter
??OrderFilter
??/receipt
錯(cuò)誤映像
可
以指定狀態(tài)代碼與Web資源之間的映像,其中的狀態(tài)代碼可以是一個(gè)HTTP響應(yīng)中返回的,也可以是由任何Web組件返回的一個(gè)Java編程語言異常中返回
的。要設(shè)置映像,必須添加一個(gè)元素到部署描述文件中。下面的元素用于將OederException映像到第14章
中使用的頁面errorpage.html。
??exception.OrderException
??/errorpage.html
注意:你也可以為包含在WAR內(nèi)的JSP頁面定義錯(cuò)誤頁面。如果錯(cuò)誤頁面是同時(shí)為WAR和JSP頁面而定義的,則JSP頁面的錯(cuò)誤頁面居先。
指向環(huán)境條目、資源環(huán)境條目或資源的引用
如
果Web組件需要引用環(huán)境條目,資源環(huán)境條目或資源(如數(shù)據(jù)庫),必須通過在Web應(yīng)用部署描述文件中的,<
resource-env-ref>或元素來聲明引用。下面的元素用于聲明一個(gè)指向某個(gè)數(shù)據(jù)源的引用,該
數(shù)據(jù)源在本指南關(guān)于Web技術(shù)的幾章中要用到。
??jdbc/BookDB
??javax.sql.DataSource
??Container
安裝Web應(yīng)用
上下文(context)是映射到一個(gè)Web應(yīng)用的名稱。例如,Hello1應(yīng)用的上下文是/hello1。為了將應(yīng)用安裝到Tomcat,需要通知Tomcat有一個(gè)新的可用上下文。
可以使用Ant
install任務(wù)來通知Tomcat有一個(gè)新的上下文。注意,在Tomcat重新啟動(dòng)之后,安裝好的應(yīng)用還不能使用。要永久地部署應(yīng)用,參見部署Web應(yīng)用。
Ant
install任務(wù)告訴由url屬性指定的在本地運(yùn)行的管理器安裝一個(gè)應(yīng)用,其上下文由path屬性指定,其安裝位置包含了由war屬性指定的該Web應(yīng)用的文件。war屬性的值可以是一個(gè)WAR文件,如:
jar:file:/path/to/bar.war!/
或者是一個(gè)解包目錄:
?file:/path/to/foo。
??username="username"
password="password" />
username和password屬性將在Tomcat Web應(yīng)用管理程序中討論。
這里無需提供一個(gè)war屬性,你可以使用config屬性來指定配置信息:
??path="mywebapp"
config="file:build/context.xml"
??username="username"
password="password"/>
config屬性指出一個(gè)配置文件包含上下文條目的格式
??docBase="../docs/tutorial/examples/web/bookstore1/build"
??debug="0">
注意,這個(gè)上下文條目通過它的docBase屬性隱式地指定了Web應(yīng)用文件的位置。
本指南示例build文件包含一個(gè)Ant
install target,它將調(diào)用Ant install 任務(wù):
??description="Install
web application" depends="build">
??
????config="file:build/context.xml"
????username="${username}"
password="${password}"/>
Ant
install任務(wù)要求Web應(yīng)用部署描述文件(web.xml)是可用的。所有的指南示例應(yīng)用都是隨一個(gè)部署描述文件一起發(fā)布的。
To
install the Hello1 application described in Web
Application Life Cycle:
要安裝Web應(yīng)用生命周期中描述的Hello1應(yīng)用,需按下列步驟:
1. 在終端窗口中,轉(zhuǎn)到<JWSDP_HOME>/docs/tutorial/examples/web/hello1.
2.確認(rèn)Tomcat已啟動(dòng)
3.執(zhí)行ant install。install target通知Tomcat新的上下文是可用的。
部署Web應(yīng)用
如果Tomcat正在運(yùn)行,就可以使用Ant
deploy任務(wù)永久地將一個(gè)上下文部署到Tomcat。
??
????war="file:/path/to/mywebapp.war"
????username="username"
password="password" />
不同于install任務(wù),install任務(wù)可以引用一個(gè)解包目錄,deploy任務(wù)需要一個(gè)WAR。該任務(wù)加載WAR到Tomcat并且啟動(dòng)應(yīng)用。也可以通過這個(gè)任務(wù)將其部署到一個(gè)遠(yuǎn)程服務(wù)器上。
下面是其他一些可用的部署方法,但是它們要求重新啟動(dòng)Tomcat:
·?? 將Web應(yīng)用目錄或WAR拷貝到/webapps。
·??
將包含了上下文條目的名為mywebapp.xml的配置文件拷貝到/webapps。上下文條目的格式在<
JWSDP_HOME>/docs/tomcat/config/context.html中的
Server Configuration Reference里有描述。注意,上下文條目通過docBase屬性隱式地指定了Web應(yīng)用文件的位置。例如,下面是在第14章中討論的應(yīng)用的上下文條目:
??
????docBase="../docs/tutorial/examples/web/
??????bookstore1/build" debug="0">
一些實(shí)例build文件包含一個(gè)像Ant
deploy 任務(wù)一樣調(diào)用的Ant deploy 目標(biāo)。
列出已安裝和部署的Web應(yīng)用
如果想列出當(dāng)前在Tomcat內(nèi)可使用所有Web應(yīng)用,你可以使用Ant
list任務(wù):
指南示例build文件包含一個(gè)像調(diào)用Ant
list 任務(wù)一樣調(diào)用的Ant list 目標(biāo)。
還可以通過運(yùn)行Manager
Application來查看列出的應(yīng)用:
http://
:8080/manager/list
運(yùn)行Web應(yīng)用
Web應(yīng)用是在Web瀏覽器引用映像到組件的URL時(shí)執(zhí)行的。一旦安裝了或者部署了Hello1應(yīng)用,便可通過將瀏覽器指向
http://
:8080/hello1/greeting
來運(yùn)行Web應(yīng)用。
用運(yùn)行Tomcat的主機(jī)名替代。如果瀏覽器運(yùn)行在與Tomcat相同的主機(jī)上,就可以用localhost替代。
更新Web應(yīng)用
在開發(fā)期間,經(jīng)常需要對(duì)Web應(yīng)用進(jìn)行修改。在修改servlet之后,必須:
1.重新編譯servlet類。
2.更新服務(wù)器上的應(yīng)用。
3.重新在客戶端裝載URL。
更新JSP頁面時(shí),無需重新編譯或重新裝載應(yīng)用,因?yàn)門omcat會(huì)自動(dòng)完成這些事情。
為了嘗試這一特征,修改Hello應(yīng)用的servlet版本。例如,你可以將GreetingServlet
返回的問候信息修改為:
Hi, my name is Duke. What's yours?
更新文件的過程為:
1.?? 編輯在源碼目錄/docs/tutorial/examples/web/hello1/src中的GreetingServlet.java文件。
2. 運(yùn)行ant build任務(wù)。該任務(wù)將servlet重新編譯到build目錄中。
更新服務(wù)器中的應(yīng)用這一過程取決于你是否使用Ant
install任務(wù)來安裝或者使用Ant deploy任務(wù)來部署這個(gè)應(yīng)用。
重新裝載Web應(yīng)用
如果你已經(jīng)使用Ant
install命令安裝了應(yīng)用,就可以使用Ant reload任務(wù)來更新服務(wù)器中的應(yīng)用:
??username="username
" password="password
" />
示例build文件包含一個(gè)
Ant remove目標(biāo),該目標(biāo)調(diào)用 Ant remove任務(wù)。從而更新服務(wù)器中的Hello1應(yīng)用,執(zhí)行ant
reload。為了觀察經(jīng)過更新的應(yīng)用,重新裝載客戶端的Hello1的URL。注意,reload
任務(wù)只改變Java類,而不會(huì)改變Web.xml文件。為了重新裝載web.xml,需要將應(yīng)用刪除
(參見移除Web應(yīng)用)并重新安裝。
在瀏覽器上你可以看到如圖4-3所示的屏幕:
圖4-3 新的問候信息
為了在該實(shí)例的JSP版本上嘗試這一特性,首先建立和部署JSP版的Hello應(yīng)用:
1.
在終端窗口中,轉(zhuǎn)到
<JWSDP_HOME>/docs/tutorial/examples/web/hello2.
2.??? 運(yùn)行ant build
。build
目標(biāo)將產(chǎn)生所有必需的編譯并且拷貝文件到
<JWSDP_HOME>/docs/tutorial/examples/web/hello2/build
目錄。
3. 運(yùn)行ant install
。install
目標(biāo)將build目錄拷貝到/webappsbuild并通知Tomcat有新的應(yīng)用。
修改某一個(gè)JSP文件。然后運(yùn)行ant
build
將經(jīng)過修改的文件拷貝到docs/tutorial/examples/web/hello2/build。記住,這里無需重新裝載服務(wù)器中的應(yīng)用,因?yàn)楫?dāng)某個(gè)JSP文件被修改時(shí),Tomcat會(huì)自動(dòng)檢測(cè)到這一情況。要查看經(jīng)過修改的應(yīng)用,
需重新裝載客戶端的Hello2的URL。
重新部署Web應(yīng)用
如果已經(jīng)通過使用Ant
deploy任務(wù)部署了應(yīng)用,就可以通過接連使用Ant undeploy
任務(wù)(見解除部署Web應(yīng)用)和Ant
deploy
任務(wù)來更新這個(gè)應(yīng)用。
移除Web應(yīng)用
如果想從服務(wù)中移除已安裝的Web應(yīng)用,可以調(diào)用
Ant remove
任務(wù):
??username="username
" password="password
" />
示例build文件包含一個(gè)
Ant remove目標(biāo),該目標(biāo)調(diào)用 Ant remove任務(wù)。
解除部署Web應(yīng)用
如果想移除一個(gè)已部署的Web應(yīng)用,可以使用Ant
undeploy任務(wù):
??username="username
" password="password
" />
一些實(shí)例build文件包含一個(gè)Ant
undeploy目標(biāo),該目標(biāo)調(diào)用Ant undeploy任務(wù)。
Web應(yīng)用的國際化和本地化
所謂的國際化是指使得應(yīng)用能夠支持各種語言和數(shù)據(jù)格式的過程。所謂本地化,是指使得一個(gè)國際化的應(yīng)用能夠支持某種特定的或者本地的語言的過程。雖然所有客戶端用戶接口都應(yīng)該被國際化和本地化,但是國際化和本地化對(duì)于Web應(yīng)用來說尤其重要,因?yàn)閃eb本身就是無所不及的。如果想要很好地鳥瞰一下國際化與本地化問題,參見
http://java.sun.com/docs/books/tutorial/i18n/index.html
有兩種方法可以用于對(duì)Web應(yīng)用進(jìn)行國際化:
·??
在每個(gè)目標(biāo)位置中提供一個(gè)JSP頁面,并且使用一個(gè)控制器servlet來發(fā)送請(qǐng)求到適當(dāng)?shù)捻撁嫔希ㄈQ于被請(qǐng)求的位置)。如果需要對(duì)一個(gè)頁面或者一個(gè)完
整的Web應(yīng)用的數(shù)據(jù)進(jìn)行國際化,這種方法比較有用。
·?? 將頁面上所有的本地敏感的數(shù)據(jù) (例如錯(cuò)誤信息,串字符或按鈕標(biāo)簽)
分離到資源束內(nèi),然后訪問這些數(shù)據(jù),來獲取響應(yīng)的翻譯過來的信息并將其插入到頁面當(dāng)中。這樣一來,就不是在代碼中直接創(chuàng)建字符串,而是創(chuàng)建一個(gè)包含了翻譯
過來的信息的資源束,然后使用相應(yīng)的關(guān)鍵字從該資源束中讀出翻譯過來的信息。資源束可以由一個(gè)文本文件(屬性資源束)或一個(gè)包含了映像的類(列表資源束)
來支持。
在
下面的關(guān)于Web技術(shù)的幾章中,Duke's
Bookstore實(shí)例被分別國際化和本地化成英語和西班牙語。關(guān)鍵字-值對(duì)包含在名為message.BookMessage_*.class的列表資
源束。為了了解在資源束中的關(guān)鍵字-值對(duì)是怎樣的,請(qǐng)看在文件messages.BookMessages.java中添加的幾行:
{"TitleCashier",
"Cashier"},
{"TitleBookDescription",
"Book Description"},
{"Visitor",
"You are visitor number "},
{"What",
"What We"re Reading"},
{"Talk",
" talks about how Web components can transform the
way
you develop applications
for the Web. This is a must read for
any self respecting
Web developer!"},
{"Start",
"Start Shopping"},
為了獲得對(duì)應(yīng)于某個(gè)給定用戶的正確字符串,Web組件從請(qǐng)求中獲取位置(由瀏覽器的語言首選項(xiàng)設(shè)定),為那個(gè)位置打開資源束,然后將該資源束作為會(huì)話屬性保存:
ResourceBundle messages
= (ResourceBundle)session.
??getAttribute("messages");
??if (messages
== null) {
????Locale
locale=request.getLocale();
????messages
= ResourceBundle.getBundle("WebMessages",
??????locale);
????session.setAttribute("messages",
messages);
??}
Web組件從會(huì)話中獲取資源束:
ResourceBundle messages
=
??(ResourceBundle)session.getAttribute("messages");
然后用下面的語句查找與關(guān)鍵字TitleCashier相關(guān)的字符串:
messages.getString("TitleCashier");
上面對(duì)國際化Web應(yīng)用的介紹非常簡要。如果要了解更多該主題的相關(guān)信息,參見Java
BluePrints:
http://java.sun.com/blueprints
今天確定了WEB開發(fā)的框架。確定采用XMLC+Tomcat+JavaBean的框架。從現(xiàn)在開始關(guān)注這方面問題!
2005年11月8日
Struts和JSF/Tapestry都屬于表現(xiàn)層框架,這兩種分屬不同性質(zhì)的框架,后者是一種事件驅(qū)動(dòng)型的組件模型,而Struts只是單純的MVC模式框架,老外總是急吼吼說事件驅(qū)動(dòng)型就比MVC模式框架好,何以見得,我們下面進(jìn)行詳細(xì)分析比較一下到底是怎么回事?
首先事件是指從客戶端頁面(瀏覽器)由用戶操作觸發(fā)的事件,Struts使用Action來接受瀏覽器表單提交的事件,這里使用了Command模式,每個(gè)繼承Action的子類都必須實(shí)現(xiàn)一個(gè)方法execute。
在struts中,實(shí)際是一個(gè)表單Form對(duì)應(yīng)一個(gè)Action類(或DispatchAction),換一句話說:在Struts中實(shí)際是一
個(gè)表單只能對(duì)應(yīng)一個(gè)事件,struts這種事件方式稱為application event,application event和component
event相比是一種粗粒度的事件。
struts重要的表單對(duì)象ActionForm是一種對(duì)象,它代表了一種應(yīng)用,這個(gè)對(duì)象中至少包含幾個(gè)字段,這些字段是Jsp頁面表單中的
input字段,因?yàn)橐粋€(gè)表單對(duì)應(yīng)一個(gè)事件,所以,當(dāng)我們需要將事件粒度細(xì)化到表單中這些字段時(shí),也就是說,一個(gè)字段對(duì)應(yīng)一個(gè)事件時(shí),單純使用
Struts就不太可能,當(dāng)然通過結(jié)合JavaScript也是可以轉(zhuǎn)彎實(shí)現(xiàn)的。
而這種情況使用JSF就可以方便實(shí)現(xiàn),
<h:inputText id="userId" value="#{login.userId}"> <f:valueChangeListener type="logindemo.UserLoginChanged" /> </h:inputText> |
#{login.userId}表示從名為login的JavaBean的getUserId獲得的結(jié)果,這個(gè)功能使用struts也可以實(shí)現(xiàn),name="login" property="userId"
關(guān)鍵是第二行,這里表示如果userId的值改變并且確定提交后,將觸發(fā)調(diào)用類UserLoginChanged的processValueChanged(...)方法。
JSF可以為組件提供兩種事件:Value Changed和 Action. 前者我們已經(jīng)在上節(jié)見識(shí)過用處,后者就相當(dāng)于struts中表單提交Action機(jī)制,它的JSF寫法如下:
<h:commandButton id="login" commandName="login"> <f:actionListener type=”logindemo.LoginActionListener” /> </h:commandButton> |
從代碼可以看出,這兩種事件是通過Listerner這樣觀察者模式貼在具體組件字段上的,而Struts此類事件是原始的一種表單提交
Submit觸發(fā)機(jī)制。如果說前者比較語言化(編程語言習(xí)慣做法類似Swing編程);后者是屬于WEB化,因?yàn)樗莵碜訦tml表單,如果你起步是從
Perl/PHP開始,反而容易接受Struts這種風(fēng)格。
基本配置
Struts和JSF都是一種框架,JSF必須需要兩種包JSF核心包、JSTL包(標(biāo)簽庫),此外,JSF還將使用到Apache項(xiàng)目的一些commons包,這些Apache包只要部署在你的服務(wù)器中既可。
JSF包下載地址:http://java.sun.com/j2ee/javaserverfaces/download.html選擇其中Reference Implementation。
JSTL包下載在http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi
所以,從JSF的驅(qū)動(dòng)包組成看,其開源基因也占據(jù)很大的比重,JSF是一個(gè)SUN伙伴們工業(yè)標(biāo)準(zhǔn)和開源之間的一個(gè)混血兒。
上述兩個(gè)地址下載的jar合并在一起就是JSF所需要的全部驅(qū)動(dòng)包了。與Struts的驅(qū)動(dòng)包一樣,這些驅(qū)動(dòng)包必須位于Web項(xiàng)目的WEB-INF/lib,和Struts一樣的是也必須在web.xml中有如下配置:
<web-app> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> </web-app> |
這里和Struts的web.xml配置何其相似,簡直一模一樣。
正如Struts的struts-config.xml一樣,JSF也有類似的faces-config.xml配置文件:
<faces-config> <navigation-rule> <from-view-id>/index.jsp</from-view-id> <navigation-case> <from-outcome>login</from-outcome> <to-view-id>/welcome.jsp</to-view-id> </navigation-case> </navigation-rule>
<managed-bean> <managed-bean-name>user</managed-bean-name> <managed-bean-class>com.corejsf.UserBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>
|
在Struts-config.xml中有ActionForm Action以及Jsp之間的流程關(guān)系,在faces-config.xml中,也有這樣的流程,我們具體解釋一下Navigation:
在index.jsp中有一個(gè)事件:
<h:commandButton label="Login" action="login" />
action的值必須匹配form-outcome值,上述Navigation配置表示:如果在index.jsp中有一個(gè)login事件,那么事件觸發(fā)后下一個(gè)頁面將是welcome.jsp
JSF有一個(gè)獨(dú)立的事件發(fā)生和頁面導(dǎo)航的流程安排,這個(gè)思路比struts要非常清晰。
managed-bean類似Struts的ActionForm,正如可以在struts-config.xml中定義ActionForm的scope一樣,這里也定義了managed-bean的scope為session。
但是如果你只以為JSF的managed-bean就這點(diǎn)功能就錯(cuò)了,JSF融入了新的Ioc模式/依賴性注射等技術(shù)。
Ioc模式
對(duì)于Userbean這樣一個(gè)managed-bean,其代碼如下:
public class UserBean {
private String name;
private String password;
// PROPERTY: name
public String getName() { return name; }
public void setName(String newValue) { name = newValue; }
// PROPERTY: password
public String getPassword() { return password; }
public void setPassword(String newValue) { password = newValue; }
}
<managed-bean> <managed-bean-name>user</managed-bean-name> <managed-bean-class>com.corejsf.UserBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope>
<managed-property> <property-name>name</property-name> <value>me</value> </managed-property>
<managed-property> <property-name>password</property-name> <value>secret</value> </managed-property> </managed-bean> |
faces-config.xml這段配置其實(shí)是將"me"賦值給name,將secret賦值給password,這是采取Ioc模式中的Setter注射方式。
Backing Beans
對(duì)于一個(gè)web form,我們可以使用一個(gè)bean包含其涉及的所有組件,這個(gè)bean就稱為Backing Bean, Backing Bean的優(yōu)點(diǎn)是:一個(gè)單個(gè)類可以封裝相關(guān)一系列功能的數(shù)據(jù)和邏輯。
說白了,就是一個(gè)Javabean里包含其他Javabean,互相調(diào)用,屬于Facade模式或Adapter模式。
對(duì)于一個(gè)Backing Beans來說,其中包含了幾個(gè)managed-bean,managed-bean一定是有scope的,那么這其中的幾個(gè)managed-beans如何配置它們的scope呢?
<managed-bean> ... <managed-property> <property-name>visit</property-name> <value>#{sessionScope.visit}</value> </managed-property>
|
這里配置了一個(gè)Backing
Beans中有一個(gè)setVisit方法,將這個(gè)visit賦值為session中的visit,這樣以后在程序中我們只管訪問visit對(duì)象,從中獲取
我們希望的數(shù)據(jù)(如用戶登陸注冊(cè)信息),而visit是保存在session還是application或request只需要配置既可。
UI界面
JSF和Struts一樣,除了JavaBeans類之外,還有頁面表現(xiàn)元素,都是是使用標(biāo)簽完成的,Struts也提供了struts-faces.tld標(biāo)簽庫向JSF過渡。
使用Struts標(biāo)簽庫編程復(fù)雜頁面時(shí),一個(gè)最大問題是會(huì)大量使用logic標(biāo)簽,這個(gè)logic如同if語句,一旦寫起來,搞的JSP頁面象俄羅斯方塊一樣,但是使用JSF標(biāo)簽就簡潔優(yōu)美:
<jia:navigatorItem name="inbox" label="InBox" icon="/images/inbox.gif" action="inbox" disabled="#{!authenticationBean.inboxAuthorized}"/>
|
如果authenticationBean中inboxAuthorized返回是假,那么這一行標(biāo)簽就不用顯示,多干凈利索!
先寫到這里,我會(huì)繼續(xù)對(duì)JSF深入比較下去,如果研究過Jdon框架的人,可能會(huì)發(fā)現(xiàn),Jdon框架的jdonframework.xml中
service配置和managed-bean一樣都使用了依賴注射,看來對(duì)Javabean的依賴注射已經(jīng)迅速地成為一種新技術(shù)象征,如果你還不了解
Ioc模式,趕緊補(bǔ)課。
附Jsf核心教程一個(gè)JSF案例:login.rar
2005年10月23日
輕量級(jí)容器可以動(dòng)態(tài)地使系統(tǒng)主要組件之間的耦合變松散。不同的容器包含相同的設(shè)計(jì)模式,但卻具有根本不同的哲學(xué)。本文幫助您在下列三種輕量級(jí)容器之間作出最佳選擇:Spring Framework、HiveMind 和 PicoContainer。
2002
年在科羅拉多的一次旅行中,我完美地感受了阿肯色河。在三段不同的漂流中,這條河展示了令人驚異的多樣性。柔美的布朗峽谷有著開闊的急流,翻滾著巨大的波
浪。Royal Gorge
別具特色的懸崖峭壁引導(dǎo)著巨大而筆直的峽谷之下的水力,在這條直線上發(fā)生一點(diǎn)小閃失都會(huì)受到長途游泳的懲罰。Numbers
具有精密的落差,需要人們?cè)诜秶M窄的圓石花園里精確操縱。在一條河里,我有了三次極不相同的體驗(yàn)。
在我的上一篇文章“輕量級(jí)開發(fā)的成功秘訣,第 3 部分:Spring 露出水面”中,我們學(xué)習(xí)了輕量級(jí)容器的基本原理。本文將向您展示三種最流行的容器:
這三種容器都源于依賴注入,但每種容器都具有極不相同的特征。當(dāng)我介紹每種容器的高級(jí)描述時(shí),您將看到正在運(yùn)行的每種框架,以及可以應(yīng)用每種框架的環(huán)境。
核心哲學(xué)
這三種容器都接受 POJO (plain old Java object),都具有對(duì)象生命周期的鉤子(所以它們可以在創(chuàng)建或銷毀 bean
時(shí)調(diào)用您的代碼),都執(zhí)行依賴注入。您可能認(rèn)為這些主旋律將導(dǎo)致相似的容器,但事實(shí)并非如此。盡管植入每種容器的代碼可能相似,但容器本身反映了不同的能
力、風(fēng)格和整體哲學(xué)。總而言之,每種容器的作者都忠于他們的哲學(xué)。
Spring Framework
作為開放源碼框架的 Geneva,Spring Framework 為數(shù)百個(gè) Java 2 Platform, Enterprise
Edition (J2EE) API 和開放源碼框架提供了輕量級(jí)容器和膠水代碼 (glue code)。Spring 有一個(gè)最重要的前景:讓
J2EE 更易使用。讀完一些示例和書籍之后,您將看到一些常見的主題:
- Spring 支持三種依賴注入——setter、構(gòu)造函數(shù) 和 方法 注入——但總的來說,最流行的模型是 setter 注入。
- 在靈活性和簡單性之間,Spring 的 XML 風(fēng)格配置更重視靈活性。您可以做任何事情,但對(duì)于初學(xué)者來說,配置文件是晦澀難懂的。
- Spring 的創(chuàng)始人認(rèn)為,容器只是整體框架的一小部分。Spring 的大部分價(jià)值來源于支持該框架的數(shù)千行膠水代碼。它易于插入任何系統(tǒng)中。
- Spring 框架是三種容器實(shí)現(xiàn)中最完美的。一般來說,優(yōu)秀的文檔都是完美編寫的。
- Spring 具有自動(dòng)連線 (autowire) 方式,但大多數(shù)示例都沒有使用它。我并不十分了解這個(gè)決策,但有時(shí)候,能夠看到明確列出的依賴關(guān)系是不錯(cuò)的。
- Spring 提供了完整的 AOP 框架,使得更容易附加服務(wù)。您可以使用 Spring 自己的框架或依賴豐富的 AspectJ 集成(參閱 參考資料)。
如果要用一個(gè)短語來形容 Spring,我會(huì)說讓企業(yè)更強(qiáng)。
HiveMind
Howard Lewis Ship 是 Jakarta Tapestry Web 框架的創(chuàng)建者,他還創(chuàng)建了
HiveMind。作為一個(gè)容器,HiveMind 是靈巧、干凈且易于使用的。與其他許多較好的開放源碼框架一樣,Ship 創(chuàng)建 HiveMind
是為了讓它幫助解決現(xiàn)實(shí)問題。但是,HiveMind 向傳統(tǒng)的輕量級(jí)容器添加了兩個(gè)創(chuàng)新:
- 最重要的 HiveMind 創(chuàng)新是模塊。據(jù) Ship 所說,Eclipse 插件激發(fā)了他的 HiveMind 模塊的靈感。
- HiveMind 強(qiáng)制您編寫接口。(與所有輕量級(jí)容器一樣,它不提供接口,而由您自己提供接口。)
- HiveMind 是用戶友好的,它提供稱為 HiveDoc 的文檔工具,友好簡明的 XML 配置,以及行準(zhǔn)確的錯(cuò)誤報(bào)告。
- HiveMind 用戶通常優(yōu)先選擇 setter 注入,但該容器還支持構(gòu)造函數(shù)注入。
如果用一個(gè)短語來形容 HiveMind 的話,我會(huì)說它是概念正確 的。
PicoContainer
到目前為止,PicoContainer 最重要的特征是它的尺寸。它沒有提供許多附加物,但它具有完整的依賴注入容器。PicoContainer 還具有一些惟一特性:
- PicoContainer 很小,所以它沒有攔截器、AOP 或相似類型的服務(wù),而選擇了讓其他框架創(chuàng)建這些服務(wù)。
- PicoContainer 支持 Java 配置技術(shù),而不支持 XML 配置技術(shù),這與其他容器一樣。
- PicoContainer 流行的使用模型是構(gòu)造函數(shù)注入,但它也支持 setter 注入。
- PicoContainer 沒有提供許多文檔,而且一些現(xiàn)有文檔是不完整的,但您不會(huì)太需要。
- PicoContainer 具有一個(gè)自動(dòng)連線方式,它很不錯(cuò)。
- PicoContainer 的發(fā)展似乎有點(diǎn)停滯。
如果用一個(gè)短語來形容 PicoContainer 的話,我會(huì)選擇理論完美,但不如 Spring 或 HiveMind 實(shí)用。
編程模型
現(xiàn)在我將向您展示社區(qū)中流行的編程示例,以幫助您更好地理解容器的作者希望您如何使用它們。我使用 PicoContainer 中的 Kiss
示例來展示 autowiring 和 Java 技術(shù)風(fēng)格的配置,使用 HiveMind 加法器示例來展示模塊能力,使用 Spring
PetClinic 應(yīng)用程序來展示 Hibernate 集成。
Kiss 示例 (PicoContainer)
在這三個(gè)容器中,PicoContainer 具有最簡單的編程模型。要查看 Kiss 示例,可從 PicoContainer.org 下載它。安裝該示例,瀏覽到 docs\Two+minute+tutorial.htm,然后您會(huì)看到兩個(gè)組件:
清單 1. 兩個(gè) Kiss 組件
public class Boy { public void kiss(Object kisser) { System.out.println("I was kissed by " + kisser); } } public class Girl { Boy boy;
public Girl(Boy boy) { this.boy = boy; }
public void kissSomeone() { boy.kiss(this); } }
|
這兩個(gè)類是自解釋的。Girl 對(duì) Boy 有依賴關(guān)系。該依賴關(guān)系將通過構(gòu)造函數(shù)被注入。先實(shí)例化一個(gè)容器:
MutablePicoContainer pico = new DefaultPicoContainer();
|
然后注冊(cè)兩個(gè)組件:
pico.registerComponentImplementation(Boy.class); pico.registerComponentImplementation(Girl.class);
|
稍后您可以向 PicoContainer 請(qǐng)求一個(gè)對(duì)象,然后操作它:
Girl girl = (Girl) pico.getComponentInstance(Girl.class); girl.kissSomeone();
|
這樣就差不多了。編程模型是優(yōu)雅的,基于構(gòu)造函數(shù)的風(fēng)格意味著您無需包括無參構(gòu)造函數(shù)。對(duì)本例中的 Girl 調(diào)用這種函數(shù)將會(huì)使該對(duì)象處于不一致的狀態(tài),因?yàn)?kiss
方法將拋出異常。
加法器示例 (HiveMind)
現(xiàn)在,讓我們看一下 HiveMind 的編程示例。從 Apache Jakarta Project 下載 HiveMind,然后查看加法器示例。您會(huì)看到接口和實(shí)現(xiàn)。(記住:HiveMind 強(qiáng)制編寫接口。)
清單 2. 加法器示例接口和實(shí)現(xiàn)
public interface Adder { public double add(double arg0, double arg1); }
public class AdderImpl implements Adder { public double add(double arg0, double arg1) { return arg0 + arg1; } }
|
將該服務(wù)暴露在 XML 文件中,如下所示:
清單 3. 將該服務(wù)暴露在 XML 文件中
<module id="examples" version="1.0.0">
<service-point id="Adder" interface="org.apache.hivemind.examples.Adder">
<create-instance class="org.apache.hivemind.examples.impl.AdderImpl"/>
</service-point> </module>
|
然后,其他應(yīng)用程序就可以使用該服務(wù)了,如下所示:
清單 4. 其他應(yīng)用程序可以使用該服務(wù)
Registry registry = RegistryBuilder.constructDefaultRegistry(); Adder adder = (Adder) registry.getService("examples.Adder", Adder.class);
... adder.add(arg0, arg1)
|
注意,HiveMind 的模塊讓您可以將多個(gè)服務(wù)組合到一起。如果您需要向容器中的服務(wù)添加功能,可以使用攔截器:
清單 5. 使用攔截器添加功能
<module id="examples" version="1.0.0"> <service-point id="Adder" interface="org.apache.hivemind.examples.Adder">
<create-instance class="org.apache.hivemind.examples.impl.AdderImpl"/>
<interceptor service-id="hivemind.LoggingInterceptor"/> </service-point> </module>
|
PetClinic 應(yīng)用程序 (Spring)
Spring 處理事情的方法有些不同。因?yàn)?Spring 框架不帶有簡單的應(yīng)用程序,我從我的書籍 Spring: A Developer's Notebook 中選擇了一個(gè)。您可以從 O'Reilly Media 獲取該示例代碼。解壓示例 4,它展示了一個(gè)用于 RentaBike 商店的帶有屬性的 CommandLineView
對(duì)象,該對(duì)象最終成為該應(yīng)用程序的數(shù)據(jù)訪問對(duì)象。
清單 6. CommandLineView 對(duì)象
public class CommandLineView { private RentABike rentaBike; public CommandLineView() {} public void setRentABike(RentABike rentaBike) {this.rentaBike = rentaBike;} public RentABike getRentaBike() { return this.rentaBike; } ... }
|
RentaBike 是具有您希望在自行車商店對(duì)象中看到的各種方法的接口:
清單 7. 接口方法
public interface RentABike { List getBikes(); Bike getBike(String serialNo); void setStoreName(String name); String getStoreName(); }
|
沒有顯示 ArrayListBikeStore
,它是 BikeStore 接口的存根實(shí)現(xiàn)。注意,Spring 允許編寫接口,但不強(qiáng)制編寫接口。下面是描述該應(yīng)用程序中 bean 的 XML 配置文件:
清單 8. 描述應(yīng)用程序 bean 的 XML 配置文件
<beans> <bean id="rentaBike" class="com.springbook.ArrayListRentABike"> <property name="storeName"><value>Bruce's Bikes</value></property> </bean> <bean id="commandLineView" class="com.springbook.CommandLineView"> <property name="rentaBike"> <ref bean="rentaBike" /> </property> </bean> </beans>
|
該上下文中有兩個(gè) bean。commandLineView
bean 依賴于 rentaBike
bean。該應(yīng)用程序通過為 rentaBike
屬性指定 rentaBike
名稱,顯式解析該依賴關(guān)系。注意,PicoContainer 自動(dòng)連接這種顯式關(guān)系,Spring 也可以,但大多數(shù)用戶不使用它的自動(dòng)連線選項(xiàng)。Spring 還允許您通過攔截器或 AOP 向外觀的任何方法添加服務(wù)。
比較
既然已經(jīng)看到每種容器的哲學(xué),下面是對(duì)每種環(huán)境的無形特性的詳細(xì)比較,比如市場份額、整體質(zhì)量(fit and finish)和整體特性列表。畢竟,即使編程模型是完美的,但如果沒有文檔,或者由于缺乏社區(qū)而您必須自己支持它,那么它也不會(huì)成為一個(gè)好容器。
活動(dòng)社區(qū)
Spring 有一個(gè)充滿活力的社區(qū),和一個(gè)支持該框架的稱為 Interface21 的職業(yè)服務(wù)公司。這很重要,因?yàn)槟滥梢垣@得良好的支持,公司才有動(dòng)力來支持 Spring 框架。我在社區(qū)的經(jīng)歷簡直太美好了。Spring 貢獻(xiàn)者、創(chuàng)始人和用戶都以杰出的內(nèi)容填滿了留言板。
HiveMind 框架是一個(gè) Apache Jakarta 項(xiàng)目,所以有著扎實(shí)的基礎(chǔ)。它有一個(gè)正在成長的萌芽社區(qū)。該框架的創(chuàng)始人
Howard Lewis Ship 是獨(dú)立顧問、優(yōu)秀導(dǎo)師和不屈不撓的提倡者。但是,要利用 HiveMind 的質(zhì)量幫助或者查找其 Web
站點(diǎn)之外的內(nèi)容仍然十分困難。盡管如此,它的在線幫助似乎不錯(cuò),而且社區(qū)似乎正在成長。Hibernate
獲得了有趣的勝利,它被選中——或者更應(yīng)該說,Ship 被選中——組成 TheServerSide.com
的新基礎(chǔ)設(shè)施,TheServerSide.com 是最重要的 Java 技術(shù)社區(qū)之一。
PicoContainer 也是一個(gè) Apache Jakarta 項(xiàng)目,它似乎發(fā)展緩慢。截止本文撰稿,PicoContainer
的最后一次主要代碼發(fā)行是在 2004 年 11 月。您看不到太多有關(guān) PicoContainer 的新文章,這有點(diǎn)慚愧,因?yàn)槲蚁矚g
PicoContainer 的一些哲學(xué)。事實(shí)上,我不太確定有沒有三種開放源碼輕量級(jí)容器的空間,尤其是最近第四種輕量級(jí)容器項(xiàng)目 Avalon
關(guān)閉之后。
就每個(gè)社區(qū)生成的活動(dòng)而言,Spring 無疑是優(yōu)勝者。Interface21 的支持、奇思妙想的論壇、活躍的郵件列表以及社區(qū)的跟蹤記錄都是無與倫比的。
整體質(zhì)量
社區(qū)的大小和實(shí)力通常驅(qū)動(dòng)開放源碼項(xiàng)目的整體質(zhì)量。充滿活力的社區(qū)需要更好的文檔和示例,而且它們會(huì)參與完成結(jié)尾的詳細(xì)信息。
Spring 團(tuán)隊(duì)編寫了可與我見過的一些比較好的商業(yè)產(chǎn)品相媲美的文檔。如果這還不夠的話,您還可以找到至少五本主要 Spring
書籍和其他許多包含 Spring 內(nèi)容的出版物。(我自己曾撰寫過兩本有關(guān) Spring 的書籍,其中一本書中包括 Jolt-winning Better, Faster, Lighter Java 一章,另一本是快速入門書籍 Spring: A Developer's Notebook)。錯(cuò)誤消息是專業(yè)性和描述性的。與第三方框架和 API 的集成是所有 Java 技術(shù)框架中最好的。包裝是經(jīng)過深思熟慮的,不過略有多余。(它幫助我開始把一些比較小的項(xiàng)目劃分成模塊。)示例是優(yōu)秀且有指導(dǎo)意義的。
與 Tapestry 一樣,HiveMind 也具有好的整體質(zhì)量。Ship 自己以那些讓 HiveMind
變得簡單易用的特性而自豪,比如行準(zhǔn)確的錯(cuò)誤報(bào)告;友好簡明的 XML 語法;良好的文檔工具 HiveDoc。與用于低級(jí)詳細(xì)信息的 JavaDoc
文檔結(jié)合使用,您可以更好地描述您的應(yīng)用程序(HiveMind 模塊)的高級(jí)特性,從而完善它們之間的依賴關(guān)系。
PicoContainer 編程模型感覺自然,但文檔不完整(許多方法標(biāo)記看起來過時(shí)好幾個(gè)月了),而且沒有許多使用該容器的真實(shí)世界示例。有時(shí)候,我會(huì)覺得自己在獨(dú)自穿過鬼魂出沒的破屋。
但使用 PicoContainer 確實(shí)有一個(gè)主要優(yōu)點(diǎn)。因?yàn)槟渲矛F(xiàn)實(shí)世界的對(duì)象時(shí),會(huì)得到一些編譯時(shí)錯(cuò)誤檢查。實(shí)際上,該容器太小太輕了,以至于除了基本配置之外,沒有什么能出錯(cuò)。PicoContainer 做了一項(xiàng)合理的工作。
特性
我不想過多地討論特性。如果您正在尋找許多膠水代碼來減少您的開放源碼收藏夾的集成或某特定 J2EE API,Spring
無疑是最佳選擇。HiveMind 不嘗試參與競爭。相反,它與 Spring 的服務(wù)兼容。PicoContainer
不構(gòu)建而且也不嘗試構(gòu)建附加物,而是選擇讓開放源碼項(xiàng)目為其提供服務(wù)。到目前為止,它的效果不太好。
哪一個(gè)最好?
目前,只有一個(gè)真正的答案。HiveMind 具有有趣的創(chuàng)新,PicoContainer
具有易于使用的模型(理論上),但社區(qū)似乎已經(jīng)投票選擇了 Spring Framework。隨著時(shí)間的推移,新的容器可能會(huì)成長,HiveMind
可能不斷獲得市場份額,但目前,Spring 是您的最佳選擇。
如果您愿意冒一些險(xiǎn),而使用不太成熟或不太流行的容器,您可能決定實(shí)現(xiàn) HiveMind(如果需要模塊級(jí)別的配置)或
PicoContainer(如果想要微小的容器)。如果需要許多膠水代碼來集成持久引擎、事務(wù)處理策略和安全性等方面,Spring
具有最完整的組件堆。但請(qǐng)記住:您可以在 HiveMind 容器中使用 Spring 組件。
2005年10月10日
這是第一次使用,試發(fā)!以后將在這里寫寫自己的學(xué)習(xí)Java的經(jīng)歷和心情!