Tomcat性能調(diào)整
作者:佚名 轉(zhuǎn)貼自:CSDN 點(diǎn)擊數(shù):15554
一. 引言
性能測(cè)試與分析是軟件開發(fā)過程中介于架構(gòu)和調(diào)整的一個(gè)廣泛并比較不容易理解的領(lǐng)域,更是一項(xiàng)較為復(fù)雜的活動(dòng)。就像下棋游戲一樣,有效的性能測(cè)試和分析只能在一個(gè)良好的計(jì)劃策略和具備了對(duì)不可預(yù)料事件的處理能力的條件下順利地完成。一個(gè)下棋高手贏得比賽靠的不僅僅是對(duì)游戲規(guī)則的認(rèn)識(shí),更是靠他的自己的能力和不斷地專注于分析自己對(duì)手的實(shí)力來更加有效地利用和發(fā)揮規(guī)則的作用。同樣一個(gè)優(yōu)秀的性能測(cè)試和分析人員將要面對(duì)的是來自一個(gè)全新的應(yīng)用程序和環(huán)境下帶來的整個(gè)項(xiàng)目的挑戰(zhàn)。本文中作者結(jié)合自己的使用經(jīng)驗(yàn)和參考文檔,對(duì)Tomcat性能方面的調(diào)整做一簡(jiǎn)要的介紹,并給出Tomcat性能的測(cè)試、分析和調(diào)整優(yōu)化的一些方法。
二. 測(cè)量Web服務(wù)器的性能
測(cè)量web服務(wù)器的性能是一項(xiàng)讓人感到畏縮的任務(wù),但是我們?cè)谶@里將給出一些需要注意的地方并且指點(diǎn)你了解其中更多的細(xì)節(jié)性的內(nèi)容。它不像一些簡(jiǎn)單的任務(wù),如測(cè)量CPU的速率或者是測(cè)量程序占用CPU的比例,web服務(wù)器的性能優(yōu)化中包括許調(diào)整許多變量來達(dá)到目標(biāo)。許多的測(cè)量策略中都包含了一個(gè)看似簡(jiǎn)單的瀏覽實(shí)際上是在向服務(wù)器發(fā)送大量的請(qǐng)求,我們稱之為客戶端的程序,來測(cè)量響應(yīng)時(shí)間??蛻舳撕头?wù)器端是在同一臺(tái)機(jī)器上嗎?服務(wù)器在測(cè)試的時(shí)候還運(yùn)行著其它的什么程序嗎?客戶端和服務(wù)器端的通訊是通過局域網(wǎng),100baseT,10baseT還是使用調(diào)制解調(diào)器?客戶端是否一直重復(fù)請(qǐng)求相同的頁面,還是隨機(jī)地訪問不同的頁面?(這些影響到了服務(wù)緩存的性能)客戶端發(fā)送請(qǐng)求的有規(guī)律的還是突發(fā)的?你是在最終的配置環(huán)境下運(yùn)行服務(wù)的還是在調(diào)試的配置環(huán)境下運(yùn)行服務(wù)的?客戶端請(qǐng)求中包含圖片還是只有HTML頁面?是否有請(qǐng)求是通過servlets和JSP的,CGI程序,服務(wù)端包含(Server-Side Includes ,SSI是一個(gè)可以讓你使用動(dòng)態(tài)HTML文件的技術(shù))?所有這些都將是我們要關(guān)心的,并且?guī)缀跷覀儾豢赡芫_地把所有的問題都清楚地列出來。
1.壓力測(cè)試工具
“工欲善其事,必先利其器”,壓力測(cè)試只有借助于一些工具才可得以實(shí)施。
大多數(shù)web壓力測(cè)試工具的實(shí)現(xiàn)原理都是通過重復(fù)的大量的頁面請(qǐng)求來模擬多用戶對(duì)被測(cè)系統(tǒng)的并發(fā)訪問,以此達(dá)到產(chǎn)生壓力的目的。產(chǎn)生壓力的手段都是通過錄制或者是編寫壓力腳本,這些腳本以多個(gè)進(jìn)程或者線程的形式在客戶端運(yùn)行,這樣通過人為制造各種類型的壓力,我們可以觀察被測(cè)系統(tǒng)在各種壓力狀況下的表現(xiàn),從而定位系統(tǒng)瓶頸,作為系統(tǒng)調(diào)優(yōu)的基礎(chǔ)。目前已經(jīng)存在的性能測(cè)試工具林林總總,數(shù)量不下一百種,從單一的開放源碼的免費(fèi)小工具如 Aapache 自帶的 web 性能測(cè)試工具 Apache Benchmark、開源的Jmeter 到大而全的商業(yè)性能測(cè)試軟件如 Mercury 的 LoadRunner 等等。任何性能測(cè)試工具都有其優(yōu)缺點(diǎn),我們可以根據(jù)實(shí)際情況挑選用最合適的工具。您可以在這里找到一些web壓力測(cè)試工具h(yuǎn)ttp://www.softwareqatest.com/qatweb1.html#LOAD
這里我們所使用的工具要支持web應(yīng)用服務(wù)認(rèn)證才可以,要支持接收發(fā)送cookies,不僅如此Tomcat支持多種認(rèn)證方式,比如基本認(rèn)證、基于表單的認(rèn)證、相互認(rèn)證和客戶端認(rèn)證,而一些工具僅僅支持HTTP基本認(rèn)證。真實(shí)地模擬用戶認(rèn)證是性能測(cè)試工具的一個(gè)重要的部分,因?yàn)檎J(rèn)證機(jī)制將對(duì)一個(gè)web站點(diǎn)的性能特征產(chǎn)生重要的影響?;谀阍诋a(chǎn)品中使用的不同的認(rèn)證方式,你需要從上面的工具列表中選擇使用這種特性的測(cè)試工具。
Apache Benchmark和http_load是命令行形式的工具,非常易于使用。Apache Benchmark可以模仿單獨(dú)的URL請(qǐng)求并且重復(fù)地執(zhí)行,可以使用不同的命令行參數(shù)來控制執(zhí)行迭代的次數(shù),并發(fā)用戶數(shù)等等。它的一個(gè)特點(diǎn)是可以周期性地打印出處理過程的信息,而其它工具只能給出一個(gè)全局的報(bào)告。
2.壓力測(cè)試工具介紹
三. 外部環(huán)境的調(diào)整
在Tomcat和應(yīng)用程序進(jìn)行了壓力測(cè)試后,如果您對(duì)應(yīng)用程序的性能結(jié)果不太滿意,就可以采取一些性能調(diào)整措施了,當(dāng)然了前提是應(yīng)用程序沒有問題,我們這里只講Tomcat的調(diào)整。由于Tomcat的運(yùn)行依賴于JVM,所以在這里我們把Tomcat的調(diào)整可以分為兩類來詳細(xì)描述:
外部環(huán)境調(diào)整
調(diào)整非Tomcat組件,例如Tomcat運(yùn)行的操作系統(tǒng)和運(yùn)行Tomcat的java虛擬機(jī)。
自身調(diào)整
修改Tomcat自身的參數(shù),調(diào)整Tomcat配置文件中的參數(shù)。
下面我們將詳細(xì)講解外部環(huán)境調(diào)整的有關(guān)內(nèi)容,Tomcat自身調(diào)整的內(nèi)容將在第2部分中闡述。
1.JAVA虛擬機(jī)性能優(yōu)化
Tomcat本身不能直接在計(jì)算機(jī)上運(yùn)行,需要依賴于硬件基礎(chǔ)之上的操作系統(tǒng)和一個(gè)java虛擬機(jī)。您可以選擇自己的需要選擇不同的操作系統(tǒng)和對(duì)應(yīng)的JDK的版本(只要是符合Sun發(fā)布的Java規(guī)范的),但我們推薦您使用Sun公司發(fā)布的JDK。確保您所使用的版本是最新的,因?yàn)镾un公司和其它一些公司一直在為提高性能而對(duì)java虛擬機(jī)做一些升級(jí)改進(jìn)。一些報(bào)告顯示JDK1.4在性能上比JDK1.3提高了將近10%到20%。
可以給Java虛擬機(jī)設(shè)置使用的內(nèi)存,但是如果你的選擇不對(duì)的話,虛擬機(jī)不會(huì)補(bǔ)償。可通過命令行的方式改變虛擬機(jī)使用內(nèi)存的大小。如下表所示有兩個(gè)參數(shù)用來設(shè)置虛擬機(jī)使用內(nèi)存的大小。
參數(shù) |
描述 |
-Xms<size> |
JVM初始化堆的大小 |
-Xmx<size> |
JVM堆的最大值 |
這兩個(gè)值的大小一般根據(jù)需要進(jìn)行設(shè)置。初始化堆的大小執(zhí)行了虛擬機(jī)在啟動(dòng)時(shí)向系統(tǒng)申請(qǐng)的內(nèi)存的大小。一般而言,這個(gè)參數(shù)不重要。但是有的應(yīng)用程序在大負(fù)載的情況下會(huì)急劇地占用更多的內(nèi)存,此時(shí)這個(gè)參數(shù)就是顯得非常重要,如果虛擬機(jī)啟動(dòng)時(shí)設(shè)置使用的內(nèi)存比較小而在這種情況下有許多對(duì)象進(jìn)行初始化,虛擬機(jī)就必須重復(fù)地增加內(nèi)存來滿足使用。由于這種原因,我們一般把-Xms和-Xmx設(shè)為一樣大,而堆的最大值受限于系統(tǒng)使用的物理內(nèi)存。一般使用數(shù)據(jù)量較大的應(yīng)用程序會(huì)使用持久對(duì)象,內(nèi)存使用有可能迅速地增長(zhǎng)。當(dāng)應(yīng)用程序需要的內(nèi)存超出堆的最大值時(shí)虛擬機(jī)就會(huì)提示內(nèi)存溢出,并且導(dǎo)致應(yīng)用服務(wù)崩潰。因此一般建議堆的最大值設(shè)置為可用內(nèi)存的最大值的80%。
Tomcat默認(rèn)可以使用的內(nèi)存為128MB,在較大型的應(yīng)用項(xiàng)目中,這點(diǎn)內(nèi)存是不夠的,需要調(diào)大。
Windows下,在文件{tomcat_home}/bin/catalina.bat,Unix下,在文件{tomcat_home}/bin/catalina.sh的前面,增加如下設(shè)置:
JAVA_OPTS='-Xms【初始化內(nèi)存大小】 -Xmx【可以使用的最大內(nèi)存】'
需要把這個(gè)兩個(gè)參數(shù)值調(diào)大。例如:
JAVA_OPTS='-Xms256m -Xmx512m'
表示初始化內(nèi)存為256MB,可以使用的最大內(nèi)存為512MB。
另外需要考慮的是Java提供的垃圾回收機(jī)制。虛擬機(jī)的堆大小決定了虛擬機(jī)花費(fèi)在收集垃圾上的時(shí)間和頻度。收集垃圾可以接受的速度與應(yīng)用有關(guān),應(yīng)該通過分析實(shí)際的垃圾收集的時(shí)間和頻率來調(diào)整。如果堆的大小很大,那么完全垃圾收集就會(huì)很慢,但是頻度會(huì)降低。如果你把堆的大小和內(nèi)存的需要一致,完全收集就很快,但是會(huì)更加頻繁。調(diào)整堆大小的的目的是最小化垃圾收集的時(shí)間,以在特定的時(shí)間內(nèi)最大化處理客戶的請(qǐng)求。在基準(zhǔn)測(cè)試的時(shí)候,為保證最好的性能,要把堆的大小設(shè)大,保證垃圾收集不在整個(gè)基準(zhǔn)測(cè)試的過程中出現(xiàn)。
如果系統(tǒng)花費(fèi)很多的時(shí)間收集垃圾,請(qǐng)減小堆大小。一次完全的垃圾收集應(yīng)該不超過 3-5 秒。如果垃圾收集成為瓶頸,那么需要指定代的大小,檢查垃圾收集的詳細(xì)輸出,研究 垃圾收集參數(shù)對(duì)性能的影響。一般說來,你應(yīng)該使用物理內(nèi)存的 80% 作為堆大小。當(dāng)增加處理器時(shí),記得增加內(nèi)存,因?yàn)榉峙淇梢圆⑿羞M(jìn)行,而垃圾收集不是并行的。
[NextPage]
2.操作系統(tǒng)性能優(yōu)化
這里說的操作系統(tǒng)是指運(yùn)行web服務(wù)器的系統(tǒng)軟件,當(dāng)然,不同的操作系統(tǒng)是為不同的目的而設(shè)計(jì)的。比如OpenBSD是面向安全的,因此在它的內(nèi)核中有許多的限制來防止不同形式的服務(wù)攻擊(OpenBSD的一句座右銘是“默認(rèn)是最安全的”)。這些限制或許更多地用來運(yùn)行活躍的web服務(wù)器。
而我們常用的Linux操作系統(tǒng)的目標(biāo)是易用使用,因此它有著更高的限制。使用BSD內(nèi)核的系統(tǒng)都帶有一個(gè)名為“Generic”的內(nèi)核,表明所有的驅(qū)動(dòng)器都靜態(tài)地與之相連。這樣就使系統(tǒng)易于使用,但是如果你要?jiǎng)?chuàng)建一個(gè)自定義的內(nèi)核來加強(qiáng)其中某些限制,那就需要排除不需要的設(shè)備。Linux內(nèi)核中的許多驅(qū)動(dòng)都是動(dòng)態(tài)地加載的。但是換而言之,內(nèi)存現(xiàn)在變得越來越便宜,所以因?yàn)榧虞d額外的設(shè)備驅(qū)動(dòng)就顯得不是很重要的。重要的是要有更多的內(nèi)存,并且在服務(wù)器上騰出更多的可用內(nèi)存。
小提示:雖然現(xiàn)在內(nèi)存已經(jīng)相當(dāng)?shù)谋阋?,但還是盡量不要購買便宜的內(nèi)存。那些有牌子的內(nèi)存雖然是貴一點(diǎn),但是從可靠性上來說,性價(jià)比會(huì)更高一些。
如果是在Windows操作系統(tǒng)上使用Tomcat,那么最好選擇服務(wù)器版本。因?yàn)樵诜欠?wù)器版本上,最終用戶授權(quán)數(shù)或者操作系統(tǒng)本身所能承受的用戶數(shù)、可用的網(wǎng)絡(luò)連接數(shù)或其它方面的一些方面都是有限制的。并且基于安全性的考慮,必須經(jīng)常給操作系統(tǒng)打上最新的補(bǔ)丁。
3.Tomcat與其它web服務(wù)器整合使用
雖然tomcat也可以作web服務(wù)器,但其處理靜態(tài)html的速度比不上apache,且其作為web服務(wù)器的功能遠(yuǎn)不如apache,因此我們想把a(bǔ)pache和tomcat集成起來,將html與jsp的功能部分進(jìn)行明確分工,讓tomcat只處理jsp部分,其它的由apache,IIS等這些web服務(wù)器處理,由此大大節(jié)省了tomcat有限的工作“線程”。
4.負(fù)載均衡
在負(fù)載均衡的思路下,多臺(tái)服務(wù)器為對(duì)稱方式,每臺(tái)服務(wù)器都具有同等的地位,可以單獨(dú)對(duì)外提供服務(wù)而無須其他服務(wù)器的輔助。通過負(fù)載分擔(dān)技術(shù),將外部發(fā)送來的請(qǐng)求按一定規(guī)則分配到對(duì)稱結(jié)構(gòu)中的某一臺(tái)服務(wù)器上,而接收到請(qǐng)求的服務(wù)器都獨(dú)立回應(yīng)客戶機(jī)的請(qǐng)求。
提供服務(wù)的一組服務(wù)器組成了一個(gè)應(yīng)用服務(wù)器集群(cluster),并對(duì)外提供一個(gè)統(tǒng)一的地址。當(dāng)一個(gè)服務(wù)請(qǐng)求被發(fā)至該集群時(shí),根據(jù)一定規(guī)則選擇一臺(tái)服務(wù)器,并將服務(wù)轉(zhuǎn)定向給該服務(wù)器承擔(dān),即將負(fù)載進(jìn)行均衡分?jǐn)偂?BR> 通過應(yīng)用負(fù)載均衡技術(shù),使應(yīng)用服務(wù)超過了一臺(tái)服務(wù)器只能為有限用戶提供服務(wù)的限制,可以利用多臺(tái)服務(wù)器同時(shí)為大量用戶提供服務(wù)。當(dāng)某臺(tái)服務(wù)器出現(xiàn)故障時(shí),負(fù)載均衡服務(wù)器會(huì)自動(dòng)進(jìn)行檢測(cè)并停止將服務(wù)請(qǐng)求分發(fā)至該服務(wù)器,而由其他工作正常的服務(wù)器繼續(xù)提供服務(wù),從而保證了服務(wù)的可靠性。
負(fù)載均衡實(shí)現(xiàn)的方式大概有四種:第一是通過DNS,但只能實(shí)現(xiàn)簡(jiǎn)單的輪流分配,不能處理故障,第二如果是基于MS IIS,Windows 2003 server本身就帶了負(fù)載均衡服務(wù),第三是硬件方式,通過交換機(jī)的功能或?qū)iT的負(fù)載均衡設(shè)備可以實(shí)現(xiàn),第四種是軟件方式,通過一臺(tái)負(fù)載均衡服務(wù)器進(jìn)行,上面安裝軟件。使用Apache Httpd Server做負(fù)載平衡器,Tomcat集群節(jié)點(diǎn)使用Tomcat就可以做到以上第四種方式。這種方式比較靈活,成本相對(duì)也較低。另外一個(gè)很大的優(yōu)點(diǎn)就是可以根據(jù)應(yīng)用的情況和服務(wù)器的情況采取一些策略。
[NextPage]
四. 自身調(diào)整
本節(jié)將向您詳細(xì)介紹一些加速可使Tomcat實(shí)例加速運(yùn)行的技巧和方法,無論是在什么操作系統(tǒng)或者何種Java虛擬機(jī)上。在有些情況下,您可能沒有控制部署環(huán)境上的操作系統(tǒng)或者Java虛擬機(jī)。在這種情況下,您就需要逐行了解以下的的一些建議,然而你應(yīng)該在修改后使之生效。我認(rèn)為以下方法是Tomcat性能自身調(diào)整的最佳方式。
1.禁用DNS查詢
當(dāng)web應(yīng)用程序向要記錄客戶端的信息時(shí),它也會(huì)記錄客戶端的IP地址或者通過域名服務(wù)器查找機(jī)器名轉(zhuǎn)換為IP地址。DNS查詢需要占用網(wǎng)絡(luò),并且包括可能從很多很遠(yuǎn)的服務(wù)器或者不起作用的服務(wù)器上去獲取對(duì)應(yīng)的IP的過程,這樣會(huì)消耗一定的時(shí)間。為了消除DNS查詢對(duì)性能的影響我們可以關(guān)閉DNS查詢,方式是修改server.xml文件中的enableLookups參數(shù)值:
Tomcat4
<Connector className=org.apache.coyote.tomcat4.CoyoteConnector port=80 minProcessors=5 maxProcessors=75 enableLookups=false redirectPort=8443 acceptCount=100 debug=0 connectionTimeout=20000 useURIValidationHack=false disableUploadTimeout=true />
Tomcat5
<Connector port=80 maxThreads=150 minSpareThreads=25 maxSpareThreads=75 enableLookups=false redirectPort=8443 acceptCount=100 debug=0 connectionTimeout=20000 disableUploadTimeout=true/>
除非你需要連接到站點(diǎn)的每個(gè)HTTP客戶端的機(jī)器名,否則我們建議在生產(chǎn)環(huán)境上關(guān)閉DNS查詢功能。可以通過Tomcat以外的方式來獲取機(jī)器名。這樣不僅節(jié)省了網(wǎng)絡(luò)帶寬、查詢時(shí)間和內(nèi)存,而且更小的流量會(huì)使日志數(shù)據(jù)也會(huì)變得更少,顯而易見也節(jié)省了硬盤空間。對(duì)流量較小的站點(diǎn)來說禁用DNS查詢可能沒有大流量站點(diǎn)的效果明顯,但是此舉仍不失為一良策。誰又見到一個(gè)低流量的網(wǎng)站一夜之間就流量大增呢?
2.調(diào)整線程數(shù)
另外一個(gè)可通過應(yīng)用程序的連接器(Connector)進(jìn)行性能控制的的參數(shù)是創(chuàng)建的處理請(qǐng)求的線程數(shù)。Tomcat使用線程池加速響應(yīng)速度來處理請(qǐng)求。在Java中線程是程序運(yùn)行時(shí)的路徑,是在一個(gè)程序中與其它控制線程無關(guān)的、能夠獨(dú)立運(yùn)行的代碼段。它們共享相同的地址空間。多線程幫助程序員寫出CPU最大利用率的高效程序,使空閑時(shí)間保持最低,從而接受更多的請(qǐng)求。
Tomcat4中可以通過修改minProcessors和maxProcessors的值來控制線程數(shù)。這些值在安裝后就已經(jīng)設(shè)定為默認(rèn)值并且是足夠使用的,但是隨著站點(diǎn)的擴(kuò)容而改大這些值。minProcessors服務(wù)器啟動(dòng)時(shí)創(chuàng)建的處理請(qǐng)求的線程數(shù)應(yīng)該足夠處理一個(gè)小量的負(fù)載。也就是說,如果一天內(nèi)每秒僅發(fā)生5次單擊事件,并且每個(gè)請(qǐng)求任務(wù)處理需要1秒鐘,那么預(yù)先設(shè)置線程數(shù)為5就足夠了。但在你的站點(diǎn)訪問量較大時(shí)就需要設(shè)置更大的線程數(shù),指定為參數(shù)maxProcessors的值。maxProcessors的值也是有上限的,應(yīng)防止流量不可控制(或者惡意的服務(wù)攻擊),從而導(dǎo)致超出了虛擬機(jī)使用內(nèi)存的大小。如果要加大并發(fā)連接數(shù),應(yīng)同時(shí)加大這兩個(gè)參數(shù)。web server允許的最大連接數(shù)還受制于操作系統(tǒng)的內(nèi)核參數(shù)設(shè)置,通常Windows是2000個(gè)左右,Linux是1000個(gè)左右。
在Tomcat5對(duì)這些參數(shù)進(jìn)行了調(diào)整,請(qǐng)看下表:
屬性名 |
描述 |
maxThreads |
Tomcat使用線程來處理接收的每個(gè)請(qǐng)求。這個(gè)值表示Tomcat可創(chuàng)建的最大的線程數(shù)。 |
acceptCount |
指定當(dāng)所有可以使用的處理請(qǐng)求的線程數(shù)都被使用時(shí),可以放到處理隊(duì)列中的請(qǐng)求數(shù),超過這個(gè)數(shù)的請(qǐng)求將不予處理。 |
connnectionTimeout |
網(wǎng)絡(luò)連接超時(shí),單位:毫秒。設(shè)置為0表示永不超時(shí),這樣設(shè)置有隱患的。通??稍O(shè)置為30000毫秒。 |
minSpareThreads |
Tomcat初始化時(shí)創(chuàng)建的線程數(shù)。 |
maxSpareThreads |
一旦創(chuàng)建的線程超過這個(gè)值,Tomcat就會(huì)關(guān)閉不再需要的socket線程。 |
最好的方式是多設(shè)置幾次并且進(jìn)行測(cè)試,觀察響應(yīng)時(shí)間和內(nèi)存使用情況。在不同的機(jī)器、操作系統(tǒng)或虛擬機(jī)組合的情況下可能會(huì)不同,而且并不是所有人的web站點(diǎn)的流量都是一樣的,因此沒有一刀切的方案來確定線程數(shù)的值。
[NextPage]
3.加速JSP編譯速度
當(dāng)?shù)谝淮卧L問一個(gè)JSP文件時(shí),它會(huì)被轉(zhuǎn)換為Java serverlet源碼,接著被編譯成Java字節(jié)碼。你可以控制使用哪個(gè)編譯器,默認(rèn)情況下,Tomcat使用使用命令行javac進(jìn)行使用的編譯器。也可以使用更快的編譯器,但是這里我們將介紹如何優(yōu)化它們。
另外一種方法是不要把所有的實(shí)現(xiàn)都使用JSP頁面,而是使用一些不同的java模板引擎變量。顯然這是一個(gè)跨越很大的決定,但是事實(shí)證明至少這種方法是只得研究的。如果你想了解更多有關(guān)在Tomcat可使用的模板語言,你可以參考Jason Hunter和William Crawford合著的《Java Servlet Programming 》一書(O'Reilly公司出版)。
在Tomcat 4.0中可以使用流行而且免費(fèi)的Jikes編譯器。Jikes編譯器的速度要由于Sun的Java編譯器。首先要安裝Jikes(可訪問http://oss.software.ibm.com/pub/jikes 獲得更多的信息),接著需要在環(huán)境變量中設(shè)置JIKESPATH包含系統(tǒng)運(yùn)行時(shí)所需的JAR文件。裝好Jikes以后還需要設(shè)置讓JSP編譯servlet使用Jikes,需要修改web.xml文件中jspCompilerPlugin的值:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class> org.apache.jasper.servlet.JspServlet </servlet-class> <init-param> <param-name>logVerbosityLevel</param-name> <param-value>WARNING</param-value> </init-param> <init-param> <param-name>jspCompilerPlugin</param-name> <param-value> org.apache.jasper.compiler.JikesJavaCompiler </param-value> </init-param> <init-param> <!-- <param-name> org.apache.catalina.jsp_classpath </param-name> --> <param-name>classpath</param-name> <param-value> /usr/local/jdk1.3.1-linux/jre/lib/rt.jar: /usr/local/lib/java/servletapi/servlet.ja r</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet>
在Tomcat 4.1(或更高版本),JSP的編譯由包含在Tomcat里面的Ant程序控制器直接執(zhí)行。這聽起來有一點(diǎn)點(diǎn)奇怪,但這正是Ant有意為之的一部分,有一個(gè)API文檔指導(dǎo)開發(fā)者在沒有啟動(dòng)一個(gè)新的JVM的情況下,使用Ant。這是使用Ant進(jìn)行Java開發(fā)的一大優(yōu)勢(shì)。另外,這也意味著你現(xiàn)在能夠在Ant中使用任何javac支持的編譯方式,這里有一個(gè)關(guān)于Apache Ant使用手冊(cè)的javac page列表。使用起來是容易的,因?yàn)槟阒恍枰?元素中定義一個(gè)名字叫“compiler”,并且在value中有一個(gè)支持編譯的編譯器名字,示例如下:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class> org.apache.jasper.servlet.JspServlet </servlet-class> <init-param> <param-name>logVerbosityLevel</param-name> <param-value>WARNING</param-value> </init-param> <init-param> <param-name>compiler</param-name> <param-value>jikes</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet>
Ant可用的編譯器
名稱 |
別名 |
調(diào)用的編譯器 |
classic |
javac1.1, javac1.2 |
Standard JDK 1.1/1.2 compiler |
modern |
javac1.3, javac1.4 |
Standard JDK 1.3/1.4 compiler |
jikes |
|
The Jikes compiler |
JVC |
Microsoft |
Microsoft command-line compiler from the Microsoft SDK for Java/Visual J++ |
KJC |
|
The kopi compiler |
GCJ |
|
The gcj compiler (included as part of gcc) |
SJ |
Symantec |
Symantec's Java compiler |
extJavac |
|
Runs either the modern or classic compiler in a JVM of its own |
由于JSP頁面在第一次使用時(shí)已經(jīng)被編譯,那么你可能希望在更新新的jsp頁面后馬上對(duì)它進(jìn)行編譯。實(shí)際上,這個(gè)過程完全可以自動(dòng)化,因?yàn)榭梢源_認(rèn)的是新的JSP頁面在生產(chǎn)服務(wù)器和在測(cè)試服務(wù)器上的運(yùn)行效果是一樣的。
[NextPage]
在Tomcat4的bin目錄下有一個(gè)名為jspc的腳本。它僅僅是運(yùn)行翻譯階段,而不是編譯階段,使用它可以在當(dāng)前目錄生成Java源文件。它是調(diào)試JSP頁面的一種有力的手段。
可以通過瀏覽器訪問再確認(rèn)一下編譯的結(jié)果。這樣就確保了文件被轉(zhuǎn)換成serverlet,被編譯了可直接執(zhí)行。這樣也準(zhǔn)確地模仿了真實(shí)用戶訪問JSP頁面,可以看到給用戶提供的功能。也抓緊這最后一刻修改出現(xiàn)的bug并且修改它J
Tomcat提供了一種通過請(qǐng)求來編譯JSP頁面的功能。例如,你可以在瀏覽器地址欄中輸入http://localhost:8080/examples/jsp/dates/date.jsp?jsp_precompile=true,這樣Tomcat就會(huì)編譯data.jsp而不是執(zhí)行它。此舉唾手可得,不失為一種檢驗(yàn)頁面正確性的捷徑。
4. 其它
前面我們提到過操作系統(tǒng)通過一些限制手段來防止惡意的服務(wù)攻擊,同樣Tomcat也提供了防止惡意攻擊或禁止某些機(jī)器訪問的設(shè)置。
Tomcat提供了兩個(gè)參數(shù)供你配置:RemoteHostValve 和RemoteAddrValve。
通過配置這兩個(gè)參數(shù),可以讓你過濾來自請(qǐng)求的主機(jī)或IP地址,并允許或拒絕哪些主機(jī)/IP。與之類似的,在Apache的httpd文件里有對(duì)每個(gè)目錄的允許/拒絕指定。
例如你可以把Admin Web application設(shè)置成只允許本地訪問,設(shè)置如下:
<Context path=/path/to/secret_files ...> <Valve className=org.apache.catalina.valves.RemoteAddrValve
allow=127.0.0.1 deny=/> </Context>
如果沒有給出允許主機(jī)的指定,那么與拒絕主機(jī)匹配的主機(jī)就會(huì)被拒絕,除此之外的都是允許的。與之類似,如果沒有給出拒絕主機(jī)的指定,那么與允許主機(jī)匹配的主機(jī)就會(huì)被允許,除此之外的都是拒絕的。
五. 容量計(jì)劃
容量計(jì)劃是在生產(chǎn)環(huán)境中使用Tomcat不得不提的提高性能的另一個(gè)重要的話題。如果你沒有對(duì)預(yù)期的網(wǎng)絡(luò)流量下的硬件和帶寬做考慮的話那么無論你如何做配置修改和測(cè)試都無濟(jì)于事。
這里先對(duì)提及的容量計(jì)劃作一個(gè)簡(jiǎn)要的定義:容量計(jì)劃是指評(píng)估硬件、操作系統(tǒng)和網(wǎng)絡(luò)帶寬,確定應(yīng)用服務(wù)的服務(wù)范圍,尋求適合需求和軟件特性的軟硬件的一項(xiàng)活動(dòng)。因此這里所說的軟件不僅包括Tomcat,也包括與Tomcat結(jié)合使用的任何第三方web服務(wù)器軟件。
如果在購買軟硬件或部署系統(tǒng)前你對(duì)容量計(jì)劃一無所知,不知道現(xiàn)有的軟硬件環(huán)境能夠支撐多少的訪問量,甚至更糟直到你已經(jīng)交付并且在生產(chǎn)環(huán)境上部署產(chǎn)品后才意識(shí)到配置有問題時(shí)再進(jìn)行變更可能為時(shí)已晚。此時(shí)只能增加硬件投入,增加硬盤容量甚至購買更好的服務(wù)器。如果事先做了容量計(jì)劃那么就不會(huì)搞的如此焦頭爛額了。
我們這里只介紹與Tomcat相關(guān)的內(nèi)容。
首先為了確定Tomcat使用機(jī)器的容量計(jì)劃,你應(yīng)該從一下列表項(xiàng)目種著手研究和計(jì)劃:
1. 硬件
采用什么樣的硬件體系?需要多少臺(tái)計(jì)算機(jī)?使用一個(gè)大型的,還是使用多臺(tái)小型機(jī)?每個(gè)計(jì)算機(jī)上使用幾個(gè)CPU?使用多少內(nèi)存?使用什么樣的存儲(chǔ)設(shè)備,I/O的處理速度有什么要求?怎樣維護(hù)這些計(jì)算機(jī)?不同的JVM在這些硬件上運(yùn)行的效果如何(比如IBM AIX系統(tǒng)只能在其設(shè)計(jì)的硬件系統(tǒng)上運(yùn)行)?
2. 網(wǎng)絡(luò)帶寬
帶寬的使用極限是多少?web應(yīng)用程序如何處理過多的請(qǐng)求?
3. 服務(wù)端操作系統(tǒng)
采用哪種操作系統(tǒng)作為站點(diǎn)服務(wù)器最好?在確定的操作系統(tǒng)上使用哪個(gè)JVM最好?例如,JVM在這種系統(tǒng)上是否支持本地多線程,對(duì)稱多處理?哪種系統(tǒng)可使web服務(wù)器更快、更穩(wěn)定,并且更便宜。是否支持多CPU?
[NextPage]
4. Tomcat容量計(jì)劃
以下介紹針對(duì)Tomcat做容量計(jì)劃的步驟:
1) 量化負(fù)載。如果站點(diǎn)已經(jīng)建立并運(yùn)行,可以使用前面介紹的工具模仿用戶訪問,確定資源的需求量。
2) 針對(duì)測(cè)試結(jié)果或測(cè)試過程中進(jìn)行分析。需要知道那些請(qǐng)求造成了負(fù)載過重或者使用過多的資源,并與其它請(qǐng)求做比較,這樣就確定了系統(tǒng)的瓶頸所在。例如:如果servlet在查詢數(shù)據(jù)庫的步驟上耗用較長(zhǎng)的時(shí)間,那么就需要考慮使用緩沖池來降低響應(yīng)時(shí)間。
3) 確定性能最低標(biāo)準(zhǔn)。例如,你不想讓用戶花20秒來等待結(jié)果頁面的返回,也就是說甚至在達(dá)到訪問量的極限時(shí),用戶等待的時(shí)間也不能超過20秒種(從點(diǎn)擊鏈接到看到返第一條返回?cái)?shù)據(jù))。這個(gè)時(shí)間中包含了數(shù)據(jù)庫查詢時(shí)間和文件訪問時(shí)間。同類產(chǎn)品性能在不同的公司可能有不同的標(biāo)準(zhǔn),一般最好采取同行中的最低標(biāo)準(zhǔn)或?qū)@個(gè)標(biāo)準(zhǔn)做出評(píng)估。
4) 確定如何合理使用底層資源,并逐一進(jìn)行測(cè)試。底層資源包括CPU、內(nèi)存、存儲(chǔ)器、帶寬、操作系統(tǒng)、JVM等等。在各種生產(chǎn)環(huán)境上都按順序進(jìn)行部署和測(cè)試,觀察是否符合需求。在測(cè)試Tomcat時(shí)盡量多采用幾種JVM,并且調(diào)整JVM使用內(nèi)存和Tomcat線程池的大小進(jìn)行測(cè)試。同時(shí)為了達(dá)到資源充分合理穩(wěn)定地使用的效果,還需針對(duì)測(cè)試過程中出現(xiàn)的硬件系統(tǒng)瓶頸進(jìn)行處理確定合理的資源配置。這個(gè)過程最為復(fù)雜,而且一般由于沒有可參考的值所以只能靠理論推斷和經(jīng)驗(yàn)總結(jié)。
5) 如果通過第4步的反復(fù)測(cè)試如果達(dá)到了最優(yōu)的組合,就可以在相同的生產(chǎn)環(huán)境上部署產(chǎn)品了。
此外應(yīng)牢記一定要文檔化你的測(cè)試過程和結(jié)果,因?yàn)榇撕罂赡苓€會(huì)進(jìn)行測(cè)試,這樣就可以拿以前的測(cè)試結(jié)果做為參考。另外測(cè)試過程要反復(fù)多次進(jìn)行,每次的條件可能都不一樣,因此只有記錄下來才能進(jìn)行結(jié)果比較和最佳條件的選擇。
這樣我們通過測(cè)試找到了最好的組合方式,各種資源得到了合理的配置,系統(tǒng)的性能得到了極大的提升。
六. 附加資料
很顯然本文也很難全面而詳盡地闡述性能優(yōu)化過程。如果你進(jìn)行更多研究的話可能會(huì)把性能調(diào)優(yōu)做的更好,比如Java程序的性能調(diào)整、操作系統(tǒng)的調(diào)整、各種復(fù)雜環(huán)境與應(yīng)用系統(tǒng)和其它所有與應(yīng)用程序相關(guān)的東西。在這里提供一些文中提到的一些資源、文中提到的相關(guān)內(nèi)容的鏈接以及本文的一些參考資料。
1. Web性能測(cè)試資料及工具
1) Jmeter Wiki首頁,Jmeter為一個(gè)開源的100%Java開發(fā)的性能測(cè)試工具 http://wiki.apache.org/jakarta-jmeter/
2) Apache Benchmark使用說明 http://httpd.apache.org/docs-2.0/programs/ab.html
3) 一些Java相關(guān)測(cè)試工具的介紹,包含可以與Tomcat集成進(jìn)行測(cè)試的工具 http://blog.csdn.net/wyingquan/
4) LoadRunner? 是一種預(yù)測(cè)系統(tǒng)行為和性能的工業(yè)標(biāo)準(zhǔn)級(jí)負(fù)載測(cè)試工具。它通過模擬數(shù)據(jù)以千萬計(jì)用戶來實(shí)施并發(fā)負(fù)載來對(duì)整個(gè)企業(yè)架構(gòu)進(jìn)行測(cè)試,來幫助您更快的查找和發(fā)現(xiàn)問題。 http://www.mercury.com/us/products/performance-center/loadrunner/
2. 文中介紹的相關(guān)內(nèi)容的介紹
1) Apache 2.x + Tomcat 4.x做負(fù)載均衡,描述了如何利用jk配置集群的負(fù)載均衡。 http://raibledesigns.com/tomcat/index.html
2) 容量計(jì)劃的制定,收集了許多有關(guān)制定web站點(diǎn)容量計(jì)劃的例子: http://www.capacityplanning.com/
3) 評(píng)測(cè)Tomcat5負(fù)載平衡與集群, http://www.javaresearch.org/article/showarticle.jsp?column=556&thread=19777
4) Apache與Tomcat的安裝與整合之整合篇 http://www.javaresearch.org/article/showarticle.jsp?column=23&thread=18139
5) 性能測(cè)試工具之研究,介紹了性能測(cè)試工具的原理與思路 http://www.51testing.com/emagzine/No2_2.htm
6) Java的內(nèi)存泄漏 http://www.matrix.org.cn/resource/article/409.html
7) Web服務(wù)器和應(yīng)用程序服務(wù)器有什么區(qū)別? http://www.matrix.org.cn/resource/article/1429.html
8) 詳細(xì)講解性能中數(shù)據(jù)庫集群的問題 http://www.theserverside.com/articles/article.tss?l=DB_Break
|
恭喜,你選擇開發(fā)工程師做為自已的職業(yè)
悲哀,你選擇開發(fā)工程師做為自已的職業(yè)
本文所指的開發(fā)工程師,僅指程序開發(fā)人員和以數(shù)字電路開發(fā)為主的電子工程師。
當(dāng)你選擇計(jì)算機(jī)或者電子、自控等專業(yè)進(jìn)入大學(xué)時(shí),你本來還是有機(jī)會(huì)從事其它行業(yè)的,可你畢業(yè)時(shí)執(zhí)迷不悟,仍然選擇了開發(fā)做為你的職業(yè),真是自做孽不可活。不過,歡迎你和我一樣加入這個(gè)被其它人認(rèn)為是風(fēng)光無限的“白領(lǐng)”吧。
如果你不是特別的與人世隔絕,我想你一定看過金老先生的名著《笑傲江湖》吧,里面有一門十分奇特的武功叫做"辟邪劍法",你看這個(gè)小說第一次看到這種功夫的練法時(shí),我想你當(dāng)時(shí)一定笑歪了牙“呵呵,真好玩!”,可是現(xiàn)在我很痛心的告訴你:你選擇的開發(fā)工作就是你人生路上的"辟邪劍法",而你現(xiàn)在已經(jīng)練了,并且無法再回頭。
相對(duì)同時(shí)剛出校門同學(xué)從事其它行業(yè)而言優(yōu)厚的薪水,以及不斷學(xué)習(xí)更新的專業(yè)知識(shí)不僅僅讓你感到生活的充實(shí),更滿足了你那不讓外人知的虛榮心。在剛出校門的幾年中,你經(jīng)?;仡^看看被你落在后面的同學(xué)們,在內(nèi)心憐憫他們的同時(shí),你也會(huì)對(duì)自已天天加班的努力工作感到
心里平衡:“有付出才會(huì)有回報(bào)”這句話在那幾年中你說的最多,不管是對(duì)自已的朋友們還是自已的愛人。第二句最常說的話是對(duì)公司的領(lǐng)導(dǎo):“不行我就走人!”,實(shí)際上你也真的走過幾回。對(duì)了,在這幾年中,因?yàn)槟愕慕?jīng)濟(jì)條件不錯(cuò),你開始買房、開始談戀愛、結(jié)婚、開始有了自已的小孩。有時(shí)候你會(huì)對(duì)自已說再過兩年就去買車。當(dāng)然其中可能有許多大件是需要分期付款的,但你對(duì)前途充滿了信心,你確信認(rèn)為這種日子會(huì)永遠(yuǎn)的持續(xù)下去,即使不是變得更好的話。
日子總是在這種平淡中一天天的過去,就在那么不經(jīng)意間,你突然發(fā)現(xiàn)自已已經(jīng)快30歲了,或者已經(jīng)30了,莫名的,你心里會(huì)漫延著一種說不清楚的不安情緒,你好像覺得前途并非像前幾年那樣變得越來越好,你也忽然發(fā)現(xiàn)你以前所瞧不起的同學(xué)里好像已經(jīng)有不少開著車的了,也有幾個(gè)人住著比你還大的房子,好像房款還是一次付清的,你突然明白你現(xiàn)在的生活比起你的同學(xué)來最多是中游偏上了。工作中最讓你感到心里不舒服的是,你越來越不敢對(duì)你的領(lǐng)導(dǎo)說不了,即使比你來的晚的同事升職或提薪,你也只是在私下與朋友們一起喝酒時(shí)才敢發(fā)發(fā)牢騷,在頭的面前你的聲間越來越小、笑臉是越來越溫柔。
你終于開始迷?!霸龠^幾年我會(huì)是在干什么呢?”,這句話常常出現(xiàn)在你的心里。
計(jì)算機(jī)開發(fā)工作,是一種以年輕為資本的工作,說句通俗點(diǎn)的話是“吃青春飯的”,嗯,這句話好像在一種特別的行業(yè)也聽到過。
其標(biāo)志就是一:工作的時(shí)間性非常強(qiáng),一個(gè)開發(fā)項(xiàng)目被定的時(shí)限通常是很緊張的,更有甚者,有些號(hào)稱開發(fā)管理的書里面還非常卑鄙的號(hào)召將一個(gè)項(xiàng)目切成多個(gè)小片,每個(gè)小片都定一個(gè)叫“里程碑”的東東來嚴(yán)格跟蹤開發(fā)進(jìn)度,加班加點(diǎn)在其它行業(yè)是需要加班工資的,而在開發(fā)行業(yè),加班工資好像還沒見到幾個(gè)公司發(fā)過,是啊,反正有時(shí)間限制著,你干不完我再找你算賬.所以開發(fā)工作通常有著其它工作所沒有的精神上的壓力。
一旦一個(gè)人步入而立之年,因?yàn)榧彝ズ秃⒆拥呢?fù)擔(dān),加上精力上面的衰退,加班工作時(shí)間變得越來越少,這點(diǎn)讓很多老板們感到:這些人已經(jīng)老了,不好用了。指示人事部門:“以后招開發(fā)人員限制在30歲以下!”,相對(duì)而言硬件開發(fā)會(huì)年齡方面限制會(huì)稍好一點(diǎn)點(diǎn),但也是五十步笑百步。還有一個(gè)很重要的一點(diǎn)就是:計(jì)算機(jī)這個(gè)爛東東實(shí)在是進(jìn)步的太快了,前兩年買的頂級(jí)配置電腦,現(xiàn)在怎么看怎么像廢品,這還是小事,更可氣的是好像每天都需要學(xué)習(xí)新的知識(shí),剛畢業(yè)時(shí)只會(huì)書本上的PASCAL,學(xué)會(huì)了用腐蝕的辦法來做電路板,一上班就開始學(xué)習(xí)TURBOC和TANGER2.0,剛剛學(xué)會(huì),還沒來得及高興,馬上開始學(xué)Borland C++和Protel3.0,好不容易學(xué)會(huì)了,卻發(fā)現(xiàn)需要學(xué)習(xí)VC和Protel98了。單片機(jī)也是啊:Z80的指令背的很熟,工作中沒來得及用就要學(xué)8031,好好學(xué)吧,本來想著這輩子就吃它了,又發(fā)現(xiàn)又出來什么PIC、DSP、CPLD、FPGA、ARM等等....這還不包括中間要學(xué)一大堆74系列、4000系列、XX系列...IC卡居然里面還有CPU卡..如果學(xué)習(xí)的知識(shí)里每個(gè)字都能變成一分錢,我想所有的開發(fā)工程師都是腰纏萬貫的富翁。
一眼看去,這種日子好像見不到頭,年輕時(shí)樂此不彼,但現(xiàn)在你一定對(duì)自已能堅(jiān)持到什么時(shí)候感到懷疑了。我們都玩過像仙劍奇?zhèn)b傳這樣的RPG游戲,剛開始時(shí)你只是一個(gè)一名不文的少年,隨著你去打怪物、撿寶貝、學(xué)秘芨,最后終于有一天你會(huì)變成一個(gè)大英雄!那么你在實(shí)際生活中過得比那些小俠們還辛苦,為什么成不了一個(gè)生活中的大俠呢?呵呵,原因在這里:因?yàn)殚_發(fā)工作是邪門功夫,它雖然可以讓你速成的變成小資,但它最大的特點(diǎn)是經(jīng)驗(yàn)不積累!日新月異的知識(shí)更新,讓你總是感到自已在退步,你就像在RPG中的主人公,開始時(shí)就給了你一把好劍和好盔甲,而且讓你的級(jí)別很高,但讓你的經(jīng)驗(yàn)不累積,雖然剛開始打小怪物時(shí)你覺得自已很爽,但越到后來,你會(huì)發(fā)現(xiàn)你會(huì)死的很慘!比較一下你與其它非開發(fā)行業(yè)的同學(xué)你就可以知道了,例如和你學(xué)醫(yī)的同學(xué)比起來。套用岳不群他老人家說華山劍宗和氣宗的區(qū)別那段話:前十年你比你那些學(xué)醫(yī)的同學(xué)收入和地位要好的多,但十年以后你和他基本上各方面都會(huì)持平,而二十年以后你的各方面遠(yuǎn)遠(yuǎn)不能與你學(xué)醫(yī)的同學(xué)相提并論!嗯,你已經(jīng)開始不笑辟邪劍法了吧。
“敢問路在何方?路在腳下...”,不過猴兄和八戒兄這么認(rèn)為是可以的,你呢?
總結(jié)了許多開發(fā)朋友在30歲以后的生活之路,讓我們一起看看開發(fā)人員“路在何方?”那么開發(fā)人員在30歲以后都干些什么呢?
其路一:繼續(xù)做你這個(gè)很有“前途”的職業(yè)吧!
偶掰著腳指頭仔細(xì)數(shù)了數(shù),發(fā)現(xiàn)還真的有很多朋友在30歲以后還在從事開發(fā)工作,我這里說的從事,是指你還需要天天在電腦邊上編程序和畫電路板,與你手下是否有幾個(gè)小兵無關(guān),也與你是否頭上頂著什么項(xiàng)目經(jīng)理、主任工程師的帽子無關(guān),只要你還需要親自開發(fā),你就屬于這一類。其中有個(gè)年齡最大的朋友是63年的,從事醫(yī)療儀器的開發(fā)工作,35歲左右還在從事軟硬件開發(fā)工作的仍有一大堆,分析這些仍然從事開發(fā)的朋友,基本上都有以下特點(diǎn):
1 癡迷工作或者癡迷電腦,晚上八點(diǎn)到十二點(diǎn)的這段時(shí)間,基本上是在電腦桌或工作臺(tái)前渡過的。
2 不喜歡與人交住,朋友很少,常聯(lián)系的人不超過五個(gè)。
3 與朋友交往時(shí)談工作多,但一般不主動(dòng)談錢。
4 體型偏胖或偏廋,不在正常區(qū)間。
5 無未來計(jì)劃,對(duì)五年后自已生活怎么樣、從事什么工作說不清楚。
6 儉省,從不亂花錢。
即使你是還不到30歲的開發(fā)人員,你也可以看看自己對(duì)以上幾條是否符合,是否會(huì)在30歲后還從事開發(fā)職業(yè),四條疑似,五條以上基本確診你也是這類型的人。
這些朋友們通常報(bào)著過一天是一天的態(tài)度生活,到了這個(gè)年齡,也不敢再輕易的換工作了,年輕時(shí)的銳氣慢慢的也消退了。唯一不變的希望是有一天從天上掉下來一大堆錢把自己砸傷。說實(shí)在話因?yàn)樗麄兊男愿袼?,基本上可以確定他們以后不可能在職場(chǎng)上獲得更好的發(fā)展,當(dāng)個(gè)小頭頭,帶幾個(gè)人開發(fā)已經(jīng)是他們發(fā)展的頂點(diǎn)。至于以后的人生之路,不僅他們自己迷茫,可能上帝也正在頭痛。
不過像這類朋友,偶很奇怪的發(fā)現(xiàn):他們的小孩都是兒子!不知是偶然還是有什么其它說法。
簡(jiǎn)單建議:要改變命運(yùn),先改變性格:堅(jiān)持半年晚上不從事工作、游戲及電視,用此時(shí)間與人交往,你的人生會(huì)有改變。
其路二:轉(zhuǎn)行從事技術(shù)支持、行政或生產(chǎn)等工作還有一些朋友,從事了幾年的開發(fā)工作,因?yàn)樽砸巡⒎翘貏e的愛好,或者領(lǐng)導(dǎo)上面的強(qiáng)制工作安排,他們轉(zhuǎn)到了技術(shù)支持、服務(wù)或行政等工作,至少當(dāng)時(shí)從表面上看起來,他們的薪水較開發(fā)要少一些,但真正的統(tǒng)計(jì)這些人,發(fā)現(xiàn)他們之中有半數(shù)的人獲得了更好的發(fā)展,升職為服務(wù)部經(jīng)理或行政經(jīng)理等職,最歷害的一個(gè)朋友已升職為總經(jīng)理助理,進(jìn)入高層。
這類朋友當(dāng)時(shí)轉(zhuǎn)行通常并非自已志愿,屬被逼無奈或者其它原因,但顯然,擁有專業(yè)知識(shí)技術(shù)的他們顯然在非技術(shù)部門中鶴立雞群,遇到什么事情他們均可從專業(yè)的角度提出建言,久而久之,他們獲得更多的升職和加薪機(jī)會(huì)也就不足為奇。
因?yàn)椴粡氖麻_發(fā),所以經(jīng)驗(yàn)開始積累,這類的職業(yè)通常會(huì)給你一個(gè)很安定的感覺,你到30多歲后會(huì)發(fā)現(xiàn)這類職業(yè)反而比開發(fā)工作更容易獲得新的工作機(jī)會(huì)。
簡(jiǎn)單建議:你如果確定在開發(fā)部無法獲得很好的發(fā)展機(jī)會(huì),不妨轉(zhuǎn)到其它幾個(gè)部門試試,換個(gè)活法,錢少點(diǎn)就少點(diǎn)吧,機(jī)會(huì)多。
其路三:開發(fā)管理
如果你現(xiàn)在已經(jīng)是總工或開發(fā)部經(jīng)理,或者你眼看就有機(jī)會(huì)被提升為這類職務(wù),那么恭喜你,你走的是從“弼馬溫”到“斗戰(zhàn)勝佛”這條金光大路,你不僅擁有很高的專業(yè)技能,而且很顯然,你也有著很強(qiáng)的人際交往能力,你這類人根本不需要對(duì)未來有著任何的擔(dān)心,你在即使一無所有的時(shí)候也很容易白手起家。
你這種人算是練辟邪劍法練成了仙,嗯,我無話可說。
你是不是這類人也很容易區(qū)別,就像圍棋二十歲不稱國(guó)手終身無望一樣,你應(yīng)該在工作三、四年以后,也就是說二十七歲左右就會(huì)發(fā)現(xiàn)自已工作中指手劃腳的時(shí)間比親自開發(fā)的時(shí)間要多了,而且大多數(shù)這類人在這個(gè)年齡手下應(yīng)該有“兵”了,相反的,如果你快30歲了還天天埋頭于電腦前編程序和畫板子,或者30多歲了你還沒升到部門經(jīng)理(雖然你總是覺得自已很有希望),基本上可以確定你不是這類人。好了,如果你確定你是這類人,那么你唯一的想法就是盡快爬上中層和高層,因?yàn)橛袝r(shí)候人生偶然性太大,不占住坑的蘿卜很有可能被人拔出來!
簡(jiǎn)單建議:天天去你的老板家里面拖地和擦桌子!
其路四:出國(guó)或考研
有兩個(gè)搞開發(fā)后出國(guó)的朋友,其中一個(gè)甚至打工打到了一個(gè)小公司總工的位置,數(shù)據(jù)庫和軟件方面水平巨牛,但仍感覺心里不踏實(shí),于是將自己工作多年的錢忍痛掏出來,出國(guó)費(fèi)加上機(jī)票大概將自已辛苦所攢的銀子花完,然后又借了一些錢,在02年身上揣著一萬美元跑去了加拿大,在加拿大不停的重復(fù)找工作,換工作,然后再找工作的循環(huán),找的工作基本上與計(jì)算機(jī)無關(guān),不過工資總是在1500加元左右,呵呵,折成人民幣與他在國(guó)內(nèi)打工拿的基本上差不多,不過租個(gè)地下室就花了300加元,然后吃吃喝喝,再買個(gè)電腦上上網(wǎng)這類的,基本每月平均還要倒貼一點(diǎn)。前段時(shí)間給我的郵件里說,現(xiàn)在身上花的差不多只有5、6000美元了,準(zhǔn)備開個(gè)小公司,看看能不能往國(guó)內(nèi)倒騰點(diǎn)東東,做最后一搏。另外一個(gè)朋友去澳州,時(shí)間稍早一些,先是大概摘了一年多的葡萄,后來總算找了個(gè)技術(shù)工作,每天的工作是畫機(jī)械圖紙,收入還算不錯(cuò)
將近3000澳元,買了個(gè)舊車,也算是過上了資本主義生活。不過前年回來一趟,唯一的感嘆就是:在國(guó)外拿2000美元的生活,絕對(duì)不如在國(guó)內(nèi)拿5000人民幣的生活舒服。
也有兩個(gè)考研的朋友,不過其中一個(gè)嚴(yán)格的說不是做開發(fā)的出身,偏重于市場(chǎng)方面的工作性質(zhì),不過我的朋友里面考研的不多,只好湊兩個(gè)人說說,一個(gè)考研后在北京找了個(gè)工作,每個(gè)月5、6000元錢,但還是做開發(fā),生活仍然與沒考研之前沒有任何的改變,前途仍然沒見到什么大亮的光,還是搞不清楚以后再干些什么,標(biāo)準(zhǔn)的過一天算一天了。另外一個(gè)考研后在大學(xué)里面找了個(gè)工作,工資雖然比他原來打工少了不少,但畢竟終身有靠,穩(wěn)定了下來,也算修成了正果,這位哥們心情一放松下來,也開始有時(shí)間琢磨著業(yè)余時(shí)間自已做點(diǎn)什么,好像現(xiàn)在慢慢的也開始有了點(diǎn)眉目。
簡(jiǎn)單建議:這兩條路,對(duì)開發(fā)人員來說都不算是很好,出國(guó)十年前是好事,現(xiàn)在難說,考研能成功轉(zhuǎn)行的概率恐怕也不是很大,多半仍然去搞開發(fā),只不過研究生可以多干幾年罷了。
其路五:轉(zhuǎn)行到市場(chǎng)
絞盡腦汁的想想,我所知道的人之中只有兩個(gè)開發(fā)人員去了市場(chǎng),這兩個(gè)人都不能說是朋友,認(rèn)識(shí)而已。他們都是主動(dòng)要求去了市場(chǎng),結(jié)果是這兩個(gè)人均在市場(chǎng)都是干到一年左右,然后都自已開公司了。呵呵,很奇怪,極高的轉(zhuǎn)行成功率!不過仔細(xì)想想,我對(duì)這兩個(gè)人的思路佩服的五體投地。能下決心仍掉每月5、6000元的開發(fā)職位,從事一個(gè)自已并不熟悉的崗位,每月拿個(gè)2000多元+提成,但提成那是說不清楚的事情,這個(gè)決定,只能讓人感覺到他們對(duì)自已前途清晰的把握和老謀深算的心機(jī)。而且他們不去服務(wù)不去生產(chǎn),挖空心思說服領(lǐng)導(dǎo)去市場(chǎng)(市場(chǎng)部門與開發(fā)部門通常是一個(gè)公司的核心部門,進(jìn)入其實(shí)并不容易),可以說是有著長(zhǎng)遠(yuǎn)的考慮的。有技術(shù)了,再與客戶交成朋友,馬上就會(huì)產(chǎn)生很大的機(jī)遇應(yīng)該是正常的事情。
有實(shí)力,有心機(jī),也有著很強(qiáng)的決心力,這種人恐怕早在大學(xué)畢業(yè)時(shí)或更早的時(shí)候就已經(jīng)決定了自已的人生之路,他們的每一步路在若干年前早就計(jì)劃周全,現(xiàn)在看起來:學(xué)會(huì)技術(shù)->進(jìn)入市場(chǎng)->尋找商機(jī)->開公司,一條多么清楚的人生之路。但就像我們上小學(xué)中學(xué)時(shí),所有人都知道上大學(xué)是我們最清楚的人生路一樣,最后只有少數(shù)人才能真正達(dá)到目標(biāo)(當(dāng)然,現(xiàn)在擴(kuò)招的歷害是另外一回事,我是說我們那個(gè)時(shí)候,也就是:“很久很久以前,當(dāng)我像你那么大的時(shí)候”)。
簡(jiǎn)單建議:你若是這類人,我的建議是:...嗯?....那個(gè)你.你,你別走啊,我還有個(gè)事想請(qǐng)你贊助一下啊.....
其路六:開公司自已干
呵呵,看到這一條,發(fā)現(xiàn)你的眼睛已經(jīng)圓了,你肯定千百次的想過這個(gè)事情吧,咳咳,其實(shí)我從事開發(fā)的時(shí)候也是天天夢(mèng)想著這種事情。總想著過兩年找個(gè)機(jī)會(huì)就自已干,這個(gè)夢(mèng)想一年又一年的折磨著你也給著你希望??纯窗桑_發(fā)后來開公司的還真的不少,里面有成功的也有很多失敗的,通常開公司都是幾個(gè)人合伙開始的,有做技術(shù)的,有做市場(chǎng)的,幾個(gè)人一拍即合、狼狽為奸,共同策劃了這一個(gè)大活動(dòng)。一般說來能讓這幾個(gè)人下決心走出這一步,產(chǎn)品肯定是先進(jìn)的,甚至是國(guó)內(nèi)獨(dú)一無二的,市場(chǎng)也是很大的,負(fù)責(zé)市場(chǎng)的那個(gè)哥們通常會(huì)拍著胸保證可以賣出去,并悄悄地告訴你他在某主管領(lǐng)導(dǎo)是他小舅子的同學(xué)的二叔,肯定沒問題。于是你們幾個(gè)人找地點(diǎn)、注冊(cè)執(zhí)照、買了幾個(gè)破桌子,再攢了兩臺(tái)電腦,每個(gè)人又湊了幾萬銀子,公司開張了!
產(chǎn)品很快出來了,市場(chǎng)的哥們也不負(fù)重望,有幾個(gè)客戶表示要試用了,一切看起來都是如此的正常,“.......你坐在老板桌前,不停的有人來匯報(bào)工作或者找你簽字...人進(jìn)人出中...你又想起公司再窮也不能只有一把椅子的故事.....”你在夢(mèng)中笑出聲來。
是如此的順利,你們很快就有單子了,很快的單子讓你們湊的那點(diǎn)錢不夠了,你們很高興的每個(gè)人又增加了投入,拿出錢時(shí)你眼淚汪汪的數(shù)著錢說:“這就是我那生蛋的母雞啊”。你們的產(chǎn)品確實(shí)不錯(cuò),市場(chǎng)也經(jīng)營(yíng)的很好,客戶慢慢的多了起來,單子來的時(shí)候一筆接著一筆,你每天都處于興奮之中,唯一美中不足的是好像客戶回款總是會(huì)拖一些日子,不過客戶給你保證說:過幾天,過幾天就付給你們,因?yàn)榛乜羁偸窃谟?jì)劃外,所以你們?yōu)榱速Y金的流暢運(yùn)行又湊了一些錢,這個(gè)時(shí)候你有一些心事了,因?yàn)槟愕拇婵钫凵厦娴臄?shù)字已經(jīng)快趨向于零了?!皼]事,過兩個(gè)月等回款了一切都OK了,誰干事業(yè)不吃點(diǎn)苦呢?”你這么安慰著自已又投入到工作中去,資金總是在回款和生產(chǎn)經(jīng)營(yíng)費(fèi)用之間走著一個(gè)窄窄的小木橋,你的賬上總是沒有太多的錢,擴(kuò)大了的公司規(guī)模和許多意外情況,使你又一次、二次、三次的與合作者們?cè)俅瓮度肓俗砸训馁Y金,當(dāng)然,后來的錢你可能已經(jīng)是借的了.....
終于有一天,你的會(huì)計(jì)再一次告訴你,老板啊,賬上又沒現(xiàn)金了,吃過多次苦頭的你終于下決心開始重視資金的運(yùn)行了,你裁掉了一些不必要的人手,減少了開發(fā)的投入,要求市場(chǎng)人員簽單的時(shí)候必須予付XX%的款,回扣也必須等收過款后再付,同時(shí)也開始對(duì)產(chǎn)品的生產(chǎn)成本開始進(jìn)行控制。
時(shí)間一天一天的過去,因?yàn)榫範(fàn)帉?duì)手的產(chǎn)品也對(duì)你的產(chǎn)品進(jìn)行了仿造,你的產(chǎn)品慢慢變得不再先進(jìn),市場(chǎng)人員開始埋怨公司的合同資金方面規(guī)定太嚴(yán)格,不好簽單,生產(chǎn)成本的下降通常也導(dǎo)至產(chǎn)品毛病的增多,客戶也開始埋怨你的服務(wù)人員不能及時(shí)進(jìn)行服務(wù)。
終于有一天,你重新走進(jìn)了人才交流中心,以前你是來招人的,現(xiàn)在你拿著自已的簡(jiǎn)歷開始尋找一個(gè)工作
......
公司的成功與否,與產(chǎn)品有關(guān),與市場(chǎng)有關(guān),但更重要的是與資金有關(guān),產(chǎn)品與市場(chǎng)都可以通過資金來彌補(bǔ),而卻沒有任何東西可以代替
資金,凡是倒下的公司,99%與資金鏈的斷裂有關(guān)。在你決定要開公司以前,先估計(jì)一下你公司支持一年所需要的資金數(shù)額,包括人工費(fèi),生產(chǎn),場(chǎng)地,廣告宣傳、市場(chǎng)費(fèi)用、甚至電、水費(fèi)等等等等,把你所想到的一切加在一起,得出的值就是..慢..如果你沒有實(shí)際的開過公司的經(jīng)驗(yàn),你需要將此數(shù)字乘3,然后就是你開公司一年最少需要的費(fèi)用,呵呵,公司的實(shí)際運(yùn)營(yíng)所需要的錢是你想像的3倍以上,你要是不信我也沒辦法。
簡(jiǎn)單建議:開公司前最重要的是先確立你后續(xù)的資金來源!也就是說錢不夠了怎么辦?---因?yàn)槟阃度氲腻X肯定會(huì)不夠的。
其路七:第二職業(yè)
這類的朋友有不少,他們沒有脫離開發(fā)工作,但是在業(yè)余時(shí)間又不停的接項(xiàng)目或者在賣產(chǎn)品,在單位里面他們顯得并不出眾,比起其它人來說他們屬于最不愿意加班的一類.為此他們白天通常工作很勤奮.這類人也許不一定可以掙很多錢,但平均下來他們一年之中通常都可以比同事們多掙個(gè)幾萬元.有時(shí)候比上班拿得還多.但令人疑惑的是,這類人在生活中更加注重穩(wěn)定,基本上沒見到他們跳過蹧,即使私下里面已經(jīng)開了個(gè)小公司,他們通常也不會(huì)辭職.
你的旁邊有沒有這類人呢?分辨他們很容易:
--電話很多,而且更愿意來電話時(shí)離開辦公室找個(gè)沒人的旮旯通話.神秘兮兮給人一種"這家伙是不是有二奶啊?"的感覺的人,通常是這類人。這類人是女性最佳的選擇對(duì)象:很顧家,不象那些富人容易花心,而比起一般人來說,他們收入相對(duì)要高得多。但總結(jié)了一下幾位這類的開發(fā)朋友:也得出了一個(gè)令人沮喪的結(jié)論:這種人通常個(gè)子不高,體形類似桶狀.....
簡(jiǎn)單建議:這好像是開發(fā)人員最佳的出路了,但比較豐厚的收入通常讓這類人不愿意去冒風(fēng)險(xiǎn)....到現(xiàn)在為止我所認(rèn)識(shí)的這類人還沒有一個(gè)真正算是成功的。
好了,雖然偶的經(jīng)歷遠(yuǎn)遠(yuǎn)說不上豐富,也沒有什么成功之處可以自滿的,但或許因?yàn)楸绕渌笥寻V長(zhǎng)了幾歲,見過的人可能會(huì)稍多一些,所
以斗膽寫出了以上的一些文字,讓您掉牙了。
下面是偶走過開發(fā)這條路上總結(jié)出來的一點(diǎn)心得,你可以不看,但看了就千萬別把嘴咧的太大:
一、不管是給別人打工還是自已干,都要全心全意的工作,因?yàn)槟闼龅娜魏我稽c(diǎn)工作都會(huì)讓自已的人生多一點(diǎn)籌碼,這一點(diǎn)最最重要!這樣的例子我至少可以舉出兩起,優(yōu)秀的開發(fā)人員被其它新公司挖走,并給一定的股份,成為新公司的股東的例子。當(dāng)時(shí)與這樣的開發(fā)人員一個(gè)部門同時(shí)工作或更早工作的有許多人,他們平時(shí)經(jīng)常偷點(diǎn)懶,能少干點(diǎn)工作就少干點(diǎn),有時(shí)候還笑話那個(gè)平時(shí)努力工作的人傻,幾年過去了,究竟誰比誰傻?
二、多與市場(chǎng)人員交朋友,你接觸他們時(shí)可能總會(huì)覺得他們知識(shí)比你少,甚至素質(zhì)比你低,可能比你還有點(diǎn)黃。但實(shí)際上他們比你更懂這個(gè)社會(huì)!參加到他們這個(gè)圈子中去,和他們一起賭賭錢、一起聊聊天、一起洗洗桑拿、一起.....你會(huì)通過他們接觸到另外一個(gè)世界。
三、機(jī)會(huì)遠(yuǎn)比錢重要,掙不掙錢在年輕時(shí)并不是特別重要!不論是在實(shí)際生活中還是在網(wǎng)上或其它地方,如果有機(jī)會(huì)參與到除本職工作外的一些項(xiàng)目或產(chǎn)品的開發(fā)中(包括你的朋友拉你去做點(diǎn)小生意之類的非開發(fā)性質(zhì)的工作),那怕是幫忙的性質(zhì),也要積極介入,至少你會(huì)交到很多的朋友,這樣你的人生會(huì)多出很多的機(jī)會(huì)。
一個(gè)政府項(xiàng)目總結(jié)
近幾天剛剛交付驗(yàn)收了一個(gè)政府的軟件項(xiàng)目,在這個(gè)項(xiàng)目的開發(fā)過程中遇到了不少困難,包括技術(shù)上的障礙和一些實(shí)際的人為上的問題。一個(gè)項(xiàng)目之所以能成功,能讓客戶滿意,領(lǐng)導(dǎo)放心的原因可能大多都差不多,大多都是老生長(zhǎng)談的那幾條。但是一個(gè)項(xiàng)目失敗的原因卻各有各的不同。下面再根據(jù)自己的體會(huì)寫一些項(xiàng)目總結(jié),一為了總結(jié)不足,積累經(jīng)驗(yàn),二為了以后項(xiàng)目中避免犯同樣的錯(cuò)誤。
一.要和客戶有足夠有效的溝通
和客戶的溝通要貫穿整個(gè)項(xiàng)目開發(fā)的始終,從立項(xiàng)調(diào)研,需求獲取到最后的驗(yàn)收測(cè)試,后期維護(hù)。
1.要盡量多的主動(dòng)跟客戶溝通
客戶一般工作都很忙,所以要通過多種方式和客戶保持溝通,電子郵件,電話,座談,調(diào)查,會(huì)議等。最初的需求盡量保證有幾次所有與項(xiàng)目相關(guān)的部門和人員都能參加的討論會(huì),把他們的各自的工作都描述一下,盡量不要遺漏,都羅列出來,因?yàn)檫@是原始需求。這往往不容易做到,因?yàn)檎块T很難抽出時(shí)間把各部門人員集中在一起來做這些事情的,但是我們必須得這樣要求他們,要求他們把這個(gè)看成一項(xiàng)工作來抓,因?yàn)榍捌诠ぷ髯霾怀浞郑竺娴拈_發(fā)會(huì)不會(huì)很成功。在對(duì)某個(gè)功能或者需求不能確定的情況下,最好能整理成列表文檔發(fā)給客戶,讓客戶以電子版的形式重新描述一下發(fā)過來,盡量不要經(jīng)常打電話騷擾客戶,要集中把要了解東西發(fā)給客戶,以便他們集中精力來處理你問的問題。
2.要盡量保證有效的溝通
每次溝通要有一定的目的性,把溝通交流的結(jié)果用文檔的形式保存下來;需求制訂出來要得到客戶的確認(rèn),在經(jīng)過幾次反復(fù)之后會(huì)得到一個(gè)相對(duì)比較穩(wěn)定的需求,雖然客戶的需求不可能一直不變,這也是很多人搞項(xiàng)目頭疼的地方,但是我認(rèn)為客戶的需求實(shí)際上是很少改變的,改變的是你對(duì)客戶需求的理解。對(duì)客戶的每一個(gè)要求都要重視,尤其是客戶后來提到的一些改動(dòng)建議,要讓他們以書面的形式發(fā)過來,必要的時(shí)候要求負(fù)責(zé)人蓋章簽字,我們不能為了下面的下面的一個(gè)小辦事員隨便打個(gè)電話就對(duì)程序做出大的改動(dòng)。再改動(dòng)比較大的情況下,我們可以要求客戶對(duì)合同的變更追加費(fèi)用,前提是把需求做為合同的附件加進(jìn)去,防治最后驗(yàn)收的時(shí)候造成爭(zhēng)執(zhí)。
3.和客戶溝通要找準(zhǔn)對(duì)象
一般企業(yè)或者政府都有專門負(fù)責(zé)信息的人員,而且最好要求客戶那邊找一個(gè)人專門負(fù)責(zé)這個(gè)項(xiàng)目。這樣找對(duì)方了解需求的時(shí)候就不會(huì)出現(xiàn)不知道找誰的情況,客戶那邊有專人負(fù)責(zé)會(huì)帶來很多好處,這個(gè)項(xiàng)目就是因?yàn)榭蛻裟沁呚?fù)責(zé)這個(gè)項(xiàng)目的人員經(jīng)常更換而為我們項(xiàng)目的開發(fā)造成了很多的不變。
二.提高開發(fā)效率和保證項(xiàng)目質(zhì)量
政府的項(xiàng)目一般都是開始的時(shí)候不著急,你催他們準(zhǔn)備資料他們也不著急,但是一旦他們把資料準(zhǔn)備全了,都交給你了就著急了,要求對(duì)方在很短的時(shí)間內(nèi)保證質(zhì)量的把項(xiàng)目交付。所以如何提高開發(fā)效率和保證項(xiàng)目質(zhì)量是確保項(xiàng)目成功的關(guān)鍵。
1.保證良好充分的測(cè)試
當(dāng)然軟件測(cè)試的范疇很大,但是為了趕進(jìn)度我們往往不能不保證進(jìn)行所有的軟件測(cè)試。軟件的測(cè)試也是遍布整個(gè)項(xiàng)目開發(fā)周期的,我了解了一下TDD,TDD的思想很好,很適合開發(fā)中小型的項(xiàng)目,實(shí)施起來也很方便,但是不能純粹的用敏捷開發(fā)的理論,必要的文檔還是需要的。我認(rèn)為代碼模塊的單元測(cè)試,開發(fā)最后階段的集成測(cè)試和部署后的整體功能測(cè)試和用戶驗(yàn)收測(cè)試是必不可少的。項(xiàng)目進(jìn)度再緊張也要進(jìn)行單元測(cè)試,只要保證單元測(cè)試能通過,以后代碼可以慢慢重構(gòu)。集成測(cè)試保證項(xiàng)目各個(gè)模塊能良好的協(xié)作共同完成復(fù)雜的任務(wù),這點(diǎn)不能保證的話,展示給客戶的最終功能就不能保證。而功能測(cè)試和用戶驗(yàn)收測(cè)試是純粹的黑盒測(cè)試,自己內(nèi)部人員先對(duì)照原始客戶的需求進(jìn)行功能測(cè)試,列出BUG列表,經(jīng)過幾次反復(fù)修改后給客戶一個(gè)可以進(jìn)行驗(yàn)收測(cè)試的系統(tǒng)。
2.保證相對(duì)必要的文檔以及保證文檔的可用性
每個(gè)模塊的文檔要獨(dú)立起來,要實(shí)現(xiàn)的目標(biāo),測(cè)試的結(jié)果,模塊所用的數(shù)據(jù)庫的結(jié)構(gòu),存儲(chǔ)過程,設(shè)計(jì)思路,調(diào)用的接口等這些是必須的。我也不建議面面俱到的文檔,但必要的需求文檔,模塊文檔,測(cè)試文檔是必須的,我們的項(xiàng)目小的不足以讓我們?nèi)W(xué)習(xí)龐大的RUP什么的。
3.迭代開發(fā)
剛開始可以根據(jù)客戶的需求弄出一個(gè)藍(lán)圖來,交給客戶看,以便讓客戶能盡量早的知道最終的開發(fā)出來的系統(tǒng)是什么樣子的,這個(gè)藍(lán)圖要盡量直觀,一般在需求整理完畢后一周就能出來,這也是指導(dǎo)以后開發(fā)工作的東西,要完整的包含所有的域模型,便于開發(fā)人員對(duì)問題域的理解。然后把優(yōu)先級(jí)最高的一系列功能完整后出一個(gè)DEMO版給客戶,要讓客戶盡量早的發(fā)現(xiàn)正在制作的項(xiàng)目和用戶想要的結(jié)果的之間的偏離和差距,告訴你后以便你盡早的調(diào)整,別等你的正式版出來后用戶發(fā)現(xiàn)這個(gè)功能你做的不對(duì),你就傻了,那時(shí)候要改動(dòng)的地方就太多了。然后再弄完善一下給用戶個(gè)beta版,這時(shí)候就已經(jīng)接近最終版本了,可能還有一些小BUG。最后把小BUG完善修復(fù)一下給客戶正式版1.0讓客戶驗(yàn)收。至于二期項(xiàng)目以后再說,先把一期項(xiàng)目的余款結(jié)了再說,對(duì)吧。
4.制訂開發(fā)規(guī)范
開發(fā)規(guī)范訂的太死會(huì)限制程序員,每個(gè)開發(fā)人員都會(huì)有一些習(xí)慣,但是為了協(xié)作,制訂一個(gè)相對(duì)通用的規(guī)范是有必要的。包括文檔的規(guī)范,數(shù)據(jù)庫設(shè)計(jì)規(guī)范,編碼規(guī)范以及各種命名規(guī)則。盡量用一些業(yè)界通用的規(guī)范,網(wǎng)上都有,我CSDN的博客上也整理了一些,MSDN的類庫開發(fā)人員指南里面也有一些。盡管某些規(guī)范很有爭(zhēng)議,我感覺你也得選擇其中一種來做為你的項(xiàng)目開發(fā)規(guī)范。
5.建立開發(fā)基礎(chǔ)
保證機(jī)器和軟件的可用,盡量大的內(nèi)存,盡量快的處理器,操作系統(tǒng),開發(fā)工具都要到位,該想到的就得想到,還要給開發(fā)人員一個(gè)相對(duì)安靜舒適的環(huán)境,最好能很方便的喝到冰箱里的可樂,而且能在累的時(shí)候有綠色的植物看。再一個(gè)就是建立一個(gè)開發(fā)基礎(chǔ)結(jié)構(gòu),這個(gè)也頗有爭(zhēng)議,幾乎每個(gè)公司都有自己的系統(tǒng)類庫,開發(fā)框架以及配套的代碼生成工具,這都很好,在開始可以對(duì)員工做適當(dāng)?shù)呐嘤?xùn),讓他們都能體驗(yàn)自底向上設(shè)計(jì)的好處,都能用的上這個(gè)架構(gòu),你可以在架構(gòu)中要求開發(fā)人員以指定的方式實(shí)現(xiàn)某些通用的任務(wù),比如說日志記錄和錯(cuò)誤處理等,而不是讓他們使用自己習(xí)慣的方式去處理問題,因?yàn)?NET的靈活性讓實(shí)現(xiàn)一個(gè)任務(wù)有很多中方案和手段。
小節(jié):雖然這個(gè)帖子沒有討論具體技術(shù),而且都是一些空話套話,并且這些空話套話可能別人也都說的不帶說了,但我感覺還是有必要自己總結(jié)一下的。
http://onlytiancai.cnblogs.com/archive/2005/11/03/218335.html
昨天我在程序中添加了一個(gè)監(jiān)聽器,
net.risesoft.ContextListener
在修改程序時(shí)發(fā)現(xiàn)web.xml總是報(bào)錯(cuò),最后Google一下后發(fā)現(xiàn)文件內(nèi)的元素是次序。
現(xiàn)將web.xml規(guī)則經(jīng)過整理總結(jié)如下:
1 定義頭和根元素
部署描述符文件就像所有XML文件一樣,必須以一個(gè)XML頭開始。這個(gè)頭聲明可以使用的XML版本并給出文件的字符編碼。
DOCYTPE聲明必須立即出現(xiàn)在此頭之后。這個(gè)聲明告訴服務(wù)器適用的servlet規(guī)范的版本(如2.2或2.3)并指定管理此文件其余部分內(nèi)容的語法的DTD(Document Type Definition,文檔類型定義)。
所有部署描述符文件的頂層(根)元素為web-app。請(qǐng)注意,XML元素不像HTML,他們是大小寫敏感的。因此,web-App和WEB-APP都是不合法的,web-app必須用小寫。
2 部署描述符文件內(nèi)的元素次序
XML 元素不僅是大小寫敏感的,而且它們還對(duì)出現(xiàn)在其他元素中的次序敏感。例如,XML頭必須是文件中的第一項(xiàng),DOCTYPE聲明必須是第二項(xiàng),而web- app元素必須是第三項(xiàng)。在web-app元素內(nèi),元素的次序也很重要。服務(wù)器不一定強(qiáng)制要求這種次序,但它們?cè)试S(實(shí)際上有些服務(wù)器就是這樣做的)完全拒絕執(zhí)行含有次序不正確的元素的Web應(yīng)用。這表示使用非標(biāo)準(zhǔn)元素次序的web.xml文件是不可移植的。
下面的列表給出了所有可直接出現(xiàn)在web-app元素內(nèi)的合法元素所必需的次序。例如,此列表說明servlet元素必須出現(xiàn)在所有servlet-mapping元素之前。請(qǐng)注意,所有這些元素都是可選的。因此,可以省略掉某一元素,但不能把它放于不正確的位置。
l icon icon元素指出IDE和GUI工具用來表示W(wǎng)eb應(yīng)用的一個(gè)和兩個(gè)圖像文件的位置。
l display-name display-name元素提供GUI工具可能會(huì)用來標(biāo)記這個(gè)特定的Web應(yīng)用的一個(gè)名稱。
l description description元素給出與此有關(guān)的說明性文本。
l context-param context-param元素聲明應(yīng)用范圍內(nèi)的初始化參數(shù)。
l filter 過濾器元素將一個(gè)名字與一個(gè)實(shí)現(xiàn)javax.servlet.Filter接口的類相關(guān)聯(lián)。
l filter-mapping 一旦命名了一個(gè)過濾器,就要利用filter-mapping元素把它與一個(gè)或多個(gè)servlet或JSP頁面相關(guān)聯(lián)。
l listener servlet API的版本2.3增加了對(duì)事件監(jiān)聽程序的支持,事件監(jiān)聽程序在建立、修改和刪除會(huì)話或servlet環(huán)境時(shí)得到通知。Listener元素指出事件監(jiān)聽程序類。
l servlet 在向servlet或JSP頁面制定初始化參數(shù)或定制URL時(shí),必須首先命名servlet或JSP頁面。Servlet元素就是用來完成此項(xiàng)任務(wù)的。
l servlet-mapping 服務(wù)器一般為servlet提供一個(gè)缺省的URL:
http://host/webAppPrefix/servlet/ServletName。但是,常常會(huì)更改這個(gè)URL,以便servlet可以訪問初始化參數(shù)或更容易地處理相對(duì)URL。在更改缺省URL時(shí),使用servlet-mapping元素。l session-config 如果某個(gè)會(huì)話在一定時(shí)間內(nèi)未被訪問,服務(wù)器可以拋棄它以節(jié)省內(nèi)存??赏ㄟ^使用HttpSession的setMaxInactiveInterval方法明確設(shè)置單個(gè)會(huì)話對(duì)象的超時(shí)值,或者可利用session-config元素制定缺省超時(shí)值。
l mime-mapping 如果Web應(yīng)用具有想到特殊的文件,希望能保證給他們分配特定的MIME類型,則mime-mapping元素提供這種保證。
l welcom-file-list welcome-file-list元素指示服務(wù)器在收到引用一個(gè)目錄名而不是文件名的URL時(shí),使用哪個(gè)文件。
l error-page error-page元素使得在返回特定HTTP狀態(tài)代碼時(shí),或者特定類型的異常被拋出時(shí),能夠制定將要顯示的頁面。
l taglib taglib元素對(duì)標(biāo)記庫描述符文件(Tag Libraryu Descriptor file)指定別名。此功能使你能夠更改TLD文件的位置,而不用編輯使用這些文件的JSP頁面。
l resource-env-ref resource-env-ref元素聲明與資源相關(guān)的一個(gè)管理對(duì)象。
l resource-ref resource-ref元素聲明一個(gè)資源工廠使用的外部資源。
l security-constraint security-constraint元素制定應(yīng)該保護(hù)的URL。它與login-config元素聯(lián)合使用
l login-config 用login-config元素來指定服務(wù)器應(yīng)該怎樣給試圖訪問受保護(hù)頁面的用戶授權(quán)。它與sercurity-constraint元素聯(lián)合使用。
l security-role security-role元素給出安全角色的一個(gè)列表,這些角色將出現(xiàn)在servlet元素內(nèi)的security-role-ref元素的role-name子元素中。分別地聲明角色可使高級(jí)IDE處理安全信息更為容易。
l env-entry env-entry元素聲明Web應(yīng)用的環(huán)境項(xiàng)。
l ejb-ref ejb-ref元素聲明一個(gè)EJB的主目錄的引用。
l ejb-local-ref ejb-local-ref元素聲明一個(gè)EJB的本地主目錄的應(yīng)用。
3 分配名稱和定制的UL
在web.xml中完成的一個(gè)最常見的任務(wù)是對(duì)servlet或JSP頁面給出名稱和定制的URL。用servlet元素分配名稱,使用servlet-mapping元素將定制的URL與剛分配的名稱相關(guān)聯(lián)。
3.1 分配名稱
為了提供初始化參數(shù),對(duì)servlet或JSP頁面定義一個(gè)定制URL或分配一個(gè)安全角色,必須首先給servlet或JSP頁面一個(gè)名稱??赏ㄟ^ servlet元素分配一個(gè)名稱。最常見的格式包括servlet-name和servlet-class子元素(在web-app元素內(nèi)),如下所示:
Test
moreservlets.TestServlet
這表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已經(jīng)得到了注冊(cè)名Test。給 servlet一個(gè)名稱具有兩個(gè)主要的含義。首先,初始化參數(shù)、定制的URL模式以及其他定制通過此注冊(cè)名而不是類名引用此servlet。其次,可在 URL而不是類名中使用此名稱。因此,利用剛才給出的定義,URL
http://host/webAppPrefix/servlet/Test 可用于
http://host/webAppPrefix/servlet/moreservlets.TestServlet 的場(chǎng)所。
請(qǐng)記?。篨ML元素不僅是大小寫敏感的,而且定義它們的次序也很重要。例如,web-app元素內(nèi)所有servlet元素必須位于所有servlet- mapping元素(下一小節(jié)介紹)之前,而且還要位于5.6節(jié)和5.11節(jié)討論的與過濾器或文檔相關(guān)的元素(如果有的話)之前。類似地,servlet 的servlet-name子元素也必須出現(xiàn)在servlet-class之前。5.2節(jié)"部署描述符文件內(nèi)的元素次序"將詳細(xì)介紹這種必需的次序。
例如,程序清單5-1給出了一個(gè)名為TestServlet的簡(jiǎn)單servlet,它駐留在moreservlets程序包中。因?yàn)榇藄ervlet是扎根在一個(gè)名為deployDemo的目錄中的Web應(yīng)用的組成部分,所以TestServlet.class放在deployDemo/WEB- INF/classes/moreservlets中。程序清單5-2給出將放置在deployDemo/WEB-INF/內(nèi)的web.xml文件的一部分。此web.xml文件使用servlet-name和servlet-class元素將名稱Test與TestServlet.class相關(guān)聯(lián)。圖 5-1和圖5-2分別顯示利用缺省URL和注冊(cè)名調(diào)用TestServlet時(shí)的結(jié)果。
程序清單5-1 TestServlet.java
package moreservlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/** Simple servlet used to illustrate servlet naming
* and custom URLs.
*
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* ? 2002 Marty Hall; may be freely used or adapted.
*/
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String uri = request.getRequestURI();
out.println(ServletUtilities.headWithTitle("Test Servlet") +
"\n" +
"
URI: " + uri + "
\n" +
"");
}
}
程序清單5-2 web.xml(說明servlet名稱的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"
http://java.sun.com/dtd/web-app_2_3.dtd">
Test
moreservlets.TestServlet
3.2 定義定制的URL
大多數(shù)服務(wù)器具有一個(gè)缺省的serlvet URL:
http://host/webAppPrefix/servlet/packageName.ServletName。雖然在開發(fā)中使用這個(gè)URL很方便,但是我們常常會(huì)希望另一個(gè)URL用于部署。例如,可能會(huì)需要一個(gè)出現(xiàn)在Web應(yīng)用頂層的URL(如,http: //host/webAppPrefix/Anyname),并且在此URL中沒有servlet項(xiàng)。位于頂層的URL簡(jiǎn)化了相對(duì)URL的使用。此外,對(duì)許多開發(fā)人員來說,頂層URL看上去比更長(zhǎng)更麻煩的缺省URL更簡(jiǎn)短。
事實(shí)上,有時(shí)需要使用定制的URL。比如,你可能想關(guān)閉缺省URL映射,以便更好地強(qiáng)制實(shí)施安全限制或防止用戶意外地訪問無初始化參數(shù)的servlet。如果你禁止了缺省的URL,那么你怎樣訪問servlet呢?這時(shí)只有使用定制的URL了。
為了分配一個(gè)定制的URL,可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet- name元素提供了一個(gè)任意名稱,可利用此名稱引用相應(yīng)的servlet;url-pattern描述了相對(duì)于Web應(yīng)用的根目錄的URL。url- pattern元素的值必須以斜杠(/)起始。
下面給出一個(gè)簡(jiǎn)單的web.xml摘錄,它允許使用URL
http://host/webAppPrefix/UrlTest而不是http://host/webAppPrefix/servlet/Test或http: //host/webAppPrefix/servlet/moreservlets.TestServlet。請(qǐng)注意,仍然需要XML頭、 DOCTYPE聲明以及web-app封閉元素。此外,可回憶一下,XML元素出現(xiàn)地次序不是隨意的。特別是,需要把所有servlet元素放在所有 servlet-mapping元素之前。
Test
moreservlets.TestServlet
Test
/UrlTest
URL模式還可以包含通配符。例如,下面的小程序指示服務(wù)器發(fā)送所有以Web應(yīng)用的URL前綴開始,以..asp結(jié)束的請(qǐng)求到名為BashMS的servlet。
BashMS
msUtils.ASPTranslator
BashMS
/*.asp
3.3 命名JSP頁面
因?yàn)镴SP頁面要轉(zhuǎn)換成sevlet,自然希望就像命名servlet一樣命名JSP頁面。畢竟,JSP頁面可能會(huì)從初始化參數(shù)、安全設(shè)置或定制的URL中受益,正如普通的serlvet那樣。雖然JSP頁面的后臺(tái)實(shí)際上是servlet這句話是正確的,但存在一個(gè)關(guān)鍵的猜疑:即,你不知道JSP頁面的實(shí)際類名(因?yàn)橄到y(tǒng)自己挑選這個(gè)名字)。因此,為了命名JSP頁面,可將jsp-file元素替換為servlet-calss元素,如下所示:
Test
/TestPage.jsp
命名JSP頁面的原因與命名servlet的原因完全相同:即為了提供一個(gè)與定制設(shè)置(如,初始化參數(shù)和安全設(shè)置)一起使用的名稱,并且,以便能更改激活 JSP頁面的URL(比方說,以便多個(gè)URL通過相同頁面得以處理,或者從URL中去掉.jsp擴(kuò)展名)。但是,在設(shè)置初始化參數(shù)時(shí),應(yīng)該注意,JSP頁面是利用jspInit方法,而不是init方法讀取初始化參數(shù)的。
例如,程序清單5-3給出一個(gè)名為TestPage.jsp的簡(jiǎn)單JSP頁面,它的工作只是打印出用來激活它的URL的本地部分。TestPage.jsp放置在deployDemo應(yīng)用的頂層。程序清單5-4給出了用來分配一個(gè)注冊(cè)名PageName,然后將此注冊(cè)名與
http://host/webAppPrefix/UrlTest2/anything 形式的URL相關(guān)聯(lián)的web.xml文件(即,deployDemo/WEB-INF/web.xml)的一部分。
程序清單5-3 TestPage.jsp
URI: <%= request.getRequestURI() %>
程序清單5-4 web.xml(說明JSP頁命名的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"
http://java.sun.com/dtd/web-app_2_3.dtd">
PageName
/TestPage.jsp
PageName
/UrlTest2/*
4 禁止激活器servlet
對(duì)servlet 或JSP頁面建立定制URL的一個(gè)原因是,這樣做可以注冊(cè)從 init(servlet)或jspInit(JSP頁面)方法中讀取得初始化參數(shù)。但是,初始化參數(shù)只在是利用定制URL模式或注冊(cè)名訪問 servlet或JSP頁面時(shí)可以使用,用缺省URL
http://host/webAppPrefix/servlet/ServletName 訪問時(shí)不能使用。因此,你可能會(huì)希望關(guān)閉缺省URL,這樣就不會(huì)有人意外地調(diào)用初始化servlet了。這個(gè)過程有時(shí)稱為禁止激活器servlet,因?yàn)槎鄶?shù)服務(wù)器具有一個(gè)用缺省的servlet URL注冊(cè)的標(biāo)準(zhǔn)servlet,并激活缺省的URL應(yīng)用的實(shí)際servlet。
有兩種禁止此缺省URL的主要方法:
l 在每個(gè)Web應(yīng)用中重新映射/servlet/模式。
l 全局關(guān)閉激活器servlet。
重要的是應(yīng)該注意到,雖然重新映射每個(gè)Web應(yīng)用中的/servlet/模式比徹底禁止激活servlet所做的工作更多,但重新映射可以用一種完全可移植的方式來完成。相反,全局禁止激活器servlet完全是針對(duì)具體機(jī)器的,事實(shí)上有的服務(wù)器(如ServletExec)沒有這樣的選擇。下面的討論對(duì)每個(gè)Web應(yīng)用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的詳細(xì)內(nèi)容。
4.1 重新映射/servlet/URL模式
在一個(gè)特定的Web應(yīng)用中禁止以
http://host/webAppPrefix/servlet/ 開始的URL的處理非常簡(jiǎn)單。所需做的事情就是建立一個(gè)錯(cuò)誤消息servlet,并使用前一節(jié)討論的url-pattern元素將所有匹配請(qǐng)求轉(zhuǎn)向該 servlet。只要簡(jiǎn)單地使用:
/servlet/*作為servlet-mapping元素中的模式即可。
例如,程序清單5-5給出了將SorryServlet servlet(程序清單5-6)與所有以
http://host/webAppPrefix/servlet/ 開頭的URL相關(guān)聯(lián)的部署描述符文件的一部分。
程序清單5-5 web.xml(說明JSP頁命名的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"
http://java.sun.com/dtd/web-app_2_3.dtd">
Sorry
moreservlets.SorryServlet
Sorry
/servlet/*
程序清單5-6 SorryServlet.java
package moreservlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/** Simple servlet used to give error messages to
* users who try to access default servlet URLs
* (i.e.,
http://host/webAppPrefix/servlet/ServletName)* in Web applications that have disabled this
* behavior.
*
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* ? 2002 Marty Hall; may be freely used or adapted.
*/
public class SorryServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Invoker Servlet Disabled.";
out.println(ServletUtilities.headWithTitle(title) +
"\n" +
"
" + title + "
\n" +
"Sorry, access to servlets by means of\n" +
"URLs that begin with\n" +
"
http://host/webAppPrefix/servlet/\n" +
"has been disabled.\n" +
"");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
4.2 全局禁止激活器:Tomcat
Tomcat 4中用來關(guān)閉缺省URL的方法與Tomcat 3中所用的很不相同。下面介紹這兩種方法:
1.禁止激活器: Tomcat 4
Tomcat 4用與前面相同的方法關(guān)閉激活器servlet,即利用web.xml中的url-mapping元素進(jìn)行關(guān)閉。不同之處在于Tomcat使用了放在 install_dir/conf中的一個(gè)服務(wù)器專用的全局web.xml文件,而前面使用的是存放在每個(gè)Web應(yīng)用的WEB-INF目錄中的標(biāo)準(zhǔn) web.xml文件。
因此,為了在Tomcat 4中關(guān)閉激活器servlet,只需在install_dir/conf/web.xml中簡(jiǎn)單地注釋出/servlet/* URL映射項(xiàng)即可,如下所示:
再次提醒,應(yīng)該注意這個(gè)項(xiàng)是位于存放在install_dir/conf的Tomcat專用的web.xml文件中的,此文件不是存放在每個(gè)Web應(yīng)用的WEB-INF目錄中的標(biāo)準(zhǔn)web.xml。
2.禁止激活器:Tomcat3
在Apache Tomcat的版本3中,通過在install_dir/conf/server.xml中注釋出InvokerInterceptor項(xiàng)全局禁止缺省 servlet URL。例如,下面是禁止使用缺省servlet URL的server.xml文件的一部分。
5 初始化和預(yù)裝載servlet與JSP頁面
這里討論控制servlet和JSP頁面的啟動(dòng)行為的方法。特別是,說明了怎樣分配初始化參數(shù)以及怎樣更改服務(wù)器生存期中裝載servlet和JSP頁面的時(shí)刻。
5.1 分配servlet初始化參數(shù)
利用init-param元素向servlet提供初始化參數(shù),init-param元素具有param-name和param-value子元素。例如,在下面的例子中,如果initServlet servlet是利用它的注冊(cè)名(InitTest)訪問的,它將能夠從其方法中調(diào)用getServletConfig(). getInitParameter("param1")獲得"Value 1",調(diào)用getServletConfig().getInitParameter("param2")獲得"2"。
InitTest
moreservlets.InitServlet
param1
value1
param2
2
在涉及初始化參數(shù)時(shí),有幾點(diǎn)需要注意:
l 返回值。GetInitParameter的返回值總是一個(gè)String。因此,在前一個(gè)例子中,可對(duì)param2使用Integer.parseInt獲得一個(gè)int。
l JSP中的初始化。JSP頁面使用jspInit而不是init。JSP頁面還需要使用jsp-file元素代替servlet-class。
l 缺省URL。初始化參數(shù)只在通過它們的注冊(cè)名或與它們注冊(cè)名相關(guān)的定制URL模式訪問Servlet時(shí)可以使用。因此,在這個(gè)例子中,param1和 param2初始化參數(shù)將能夠在使用URL
http://host/webAppPrefix/servlet/InitTest 時(shí)可用,但在使用URL
http://host/webAppPrefix/servlet/myPackage.InitServlet 時(shí)不能使用。
例如,程序清單5-7給出一個(gè)名為InitServlet的簡(jiǎn)單servlet,它使用init方法設(shè)置firstName和emailAddress字段。程序清單5-8給出分配名稱InitTest給servlet的web.xml文件。
程序清單5-7 InitServlet.java
package moreservlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/** Simple servlet used to illustrate servlet
* initialization parameters.
*
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* ? 2002 Marty Hall; may be freely used or adapted.
*/
public class InitServlet extends HttpServlet {
private String firstName, emailAddress;
public void init() {
ServletConfig config = getServletConfig();
firstName = config.getInitParameter("firstName");
emailAddress = config.getInitParameter("emailAddress");
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String uri = request.getRequestURI();
out.println(ServletUtilities.headWithTitle("Init Servlet") +
"\n" +
"
Init Parameters:
\n" +
"
\n" +
"
- First name: " + firstName + "\n" +
"
- Email address: " + emailAddress + "\n" +
"
\n" +
"");
}
}
程序清單5-8 web.xml(說明初始化參數(shù)的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"
http://java.sun.com/dtd/web-app_2_3.dtd">
InitTest
moreservlets.InitServlet
firstName
Larry
emailAddress
Ellison@Microsoft.com
5.2 分配JSP初始化參數(shù)
給JSP頁面提供初始化參數(shù)在三個(gè)方面不同于給servlet提供初始化參數(shù)。
1)使用jsp-file而不是servlet-class。因此,WEB-INF/web.xml文件的servlet元素如下所示:
PageName
/RealPage.jsp
...
...
...
2) 幾乎總是分配一個(gè)明確的URL模式。對(duì)servlet,一般相應(yīng)地使用以
http://host/webAppPrefix/servlet/ 開始的缺省URL。只需記住,使用注冊(cè)名而不是原名稱即可。這對(duì)于JSP頁面在技術(shù)上也是合法的。例如,在上面給出的例子中,可用URL
http://host/webAppPrefix/servlet/PageName 訪問RealPage.jsp的對(duì)初始化參數(shù)具有訪問權(quán)的版本。但在用于JSP頁面時(shí),許多用戶似乎不喜歡應(yīng)用常規(guī)的servlet的URL。此外,如果 JSP頁面位于服務(wù)器為其提供了目錄清單的目錄中(如,一個(gè)既沒有index.html也沒有index.jsp文件的目錄),則用戶可能會(huì)連接到此 JSP頁面,單擊它,從而意外地激活未初始化的頁面。因此,好的辦法是使用url-pattern(5.3節(jié))將JSP頁面的原URL與注冊(cè)的 servlet名相關(guān)聯(lián)。這樣,客戶機(jī)可使用JSP頁面的普通名稱,但仍然激活定制的版本。例如,給定來自項(xiàng)目1的servlet定義,可使用下面的 servlet-mapping定義:
PageName
/RealPage.jsp
3)JSP頁使用jspInit而不是init。自動(dòng)從JSP頁面建立的servlet或許已經(jīng)使用了inti方法。因此,使用JSP聲明提供一個(gè)init方法是不合法的,必須制定jspInit方法。
為了說明初始化JSP頁面的過程,程序清單5-9給出了一個(gè)名為InitPage.jsp的JSP頁面,它包含一個(gè)jspInit方法且放置于 deployDemo Web應(yīng)用層次結(jié)構(gòu)的頂層。一般,
http://host/deployDemo/InitPage.jsp 形式的URL將激活此頁面的不具有初始化參數(shù)訪問權(quán)的版本,從而將對(duì)firstName和emailAddress變量顯示null。但是, web.xml文件(程序清單5-10)分配了一個(gè)注冊(cè)名,然后將該注冊(cè)名與URL模式/InitPage.jsp相關(guān)聯(lián)。
程序清單5-9 InitPage.jsp
Init Parameters:
- First name: <%= firstName %>
- Email address: <%= emailAddress %>
<%!
private String firstName, emailAddress;
public void jspInit() {
ServletConfig config = getServletConfig();
firstName = config.getInitParameter("firstName");
emailAddress = config.getInitParameter("emailAddress");
}
%>
程序清單5-10 web.xml(說明JSP頁面的init參數(shù)的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"
http://java.sun.com/dtd/web-app_2_3.dtd">
InitPage
/InitPage.jsp
firstName
Bill
emailAddress
gates@oracle.com
InitPage
/InitPage.jsp
5.3 提供應(yīng)用范圍內(nèi)的初始化參數(shù)
一般,對(duì)單個(gè)地servlet或JSP頁面分配初始化參數(shù)。指定的servlet或JSP頁面利用ServletConfig的 getInitParameter方法讀取這些參數(shù)。但是,在某些情形下,希望提供可由任意servlet或JSP頁面借助ServletContext 的getInitParameter方法讀取的系統(tǒng)范圍內(nèi)的初始化參數(shù)。
可利用context-param元素聲明這些系統(tǒng)范圍內(nèi)的初始化值。context-param元素應(yīng)該包含param-name、param-value以及可選的description子元素,如下所示:
support-email
blackhole@mycompany.com
可回憶一下,為了保證可移植性,web.xml內(nèi)的元素必須以正確的次序聲明。但這里應(yīng)該注意,context-param元素必須出現(xiàn)任意與文檔有關(guān)的元素(icon、display-name或description)之后及filter、filter-mapping、listener或 servlet元素之前。
5.4 在服務(wù)器啟動(dòng)時(shí)裝載servlet
假如servlet或JSP頁面有一個(gè)要花很長(zhǎng)時(shí)間執(zhí)行的init (servlet)或jspInit(JSP)方法。例如,假如init或jspInit方法從某個(gè)數(shù)據(jù)庫或ResourceBundle查找產(chǎn)量。這種情況下,在第一個(gè)客戶機(jī)請(qǐng)求時(shí)裝載servlet的缺省行為將對(duì)第一個(gè)客戶機(jī)產(chǎn)生較長(zhǎng)時(shí)間的延遲。因此,可利用servlet的load-on- startup元素規(guī)定服務(wù)器在第一次啟動(dòng)時(shí)裝載servlet。下面是一個(gè)例子。
…
…
可以為此元素體提供一個(gè)整數(shù)而不是使用一個(gè)空的load-on-startup。想法是服務(wù)器應(yīng)該在裝載較大數(shù)目的servlet或JSP頁面之前裝載較少數(shù)目的servlet或JSP頁面。例如,下面的servlet項(xiàng)(放置在Web應(yīng)用的WEB-INF目錄下的web.xml文件中的web-app元素內(nèi))將指示服務(wù)器首先裝載和初始化SearchServlet,然后裝載和初始化由位于Web應(yīng)用的result目錄中的index.jsp文件產(chǎn)生的 servlet。
Search
myPackage.SearchServlet
1
Results
/results/index.jsp
2
6 聲明過濾器
servlet版本2.3引入了過濾器的概念。雖然所有支持servlet API版本2.3的服務(wù)器都支持過濾器,但為了使用與過濾器有關(guān)的元素,必須在web.xml中使用版本2.3的DTD。
過濾器可截取和修改進(jìn)入一個(gè)servlet或JSP頁面的請(qǐng)求或從一個(gè)servlet或JSP頁面發(fā)出的相應(yīng)。在執(zhí)行一個(gè)servlet或JSP頁面之前,必須執(zhí)行第一個(gè)相關(guān)的過濾器的doFilter方法。在該過濾器對(duì)其FilterChain對(duì)象調(diào)用doFilter時(shí),執(zhí)行鏈中的下一個(gè)過濾器。如果沒有其他過濾器,servlet或JSP頁面被執(zhí)行。過濾器具有對(duì)到來的ServletRequest對(duì)象的全部訪問權(quán),因此,它們可以查看客戶機(jī)名、查找到來的cookie等。為了訪問servlet或JSP頁面的輸出,過濾器可將響應(yīng)對(duì)象包裹在一個(gè)替身對(duì)象(stand-in object)中,比方說把輸出累加到一個(gè)緩沖區(qū)。在調(diào)用FilterChain對(duì)象的doFilter方法之后,過濾器可檢查緩沖區(qū),如有必要,就對(duì)它進(jìn)行修改,然后傳送到客戶機(jī)。
例如,程序清單5-11帝國(guó)難以了一個(gè)簡(jiǎn)單的過濾器,只要訪問相關(guān)的servlet或JSP頁面,它就截取請(qǐng)求并在標(biāo)準(zhǔn)輸出上打印一個(gè)報(bào)告(開發(fā)過程中在桌面系統(tǒng)上運(yùn)行時(shí),大多數(shù)服務(wù)器都可以使用這個(gè)過濾器)。
程序清單5-11 ReportFilter.java
package moreservlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
/** Simple filter that prints a report on the standard output
* whenever the associated servlet or JSP page is accessed.
*
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* ? 2002 Marty Hall; may be freely used or adapted.
*/
public class ReportFilter implements Filter {
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest)request;
System.out.println(req.getRemoteHost() +
" tried to access " +
req.getRequestURL() +
" on " + new Date() + ".");
chain.doFilter(request,response);
}
public void init(FilterConfig config)
throws ServletException {
}
public void destroy() {}
}
一旦建立了一個(gè)過濾器,可以在web.xml中利用filter元素以及filter-name(任意名稱)、file-class(完全限定的類名)和(可選的)init-params子元素聲明它。請(qǐng)注意,元素在web.xml的web-app元素中出現(xiàn)的次序不是任意的;允許服務(wù)器(但不是必需的)強(qiáng)制所需的次序,并且實(shí)際中有些服務(wù)器也是這樣做的。但這里要注意,所有filter元素必須出現(xiàn)在任意filter-mapping元素之前, filter-mapping元素又必須出現(xiàn)在所有servlet或servlet-mapping元素之前。
例如,給定上述的ReportFilter類,可在web.xml中作出下面的filter聲明。它把名稱Reporter與實(shí)際的類ReportFilter(位于moreservlets程序包中)相關(guān)聯(lián)。
Reporter
moresevlets.ReportFilter
一旦命名了一個(gè)過濾器,可利用filter-mapping元素把它與一個(gè)或多個(gè)servlet或JSP頁面相關(guān)聯(lián)。關(guān)于此項(xiàng)工作有兩種選擇。
首先,可使用filter-name和servlet-name子元素把此過濾器與一個(gè)特定的servlet名(此servlet名必須稍后在相同的 web.xml文件中使用servlet元素聲明)關(guān)聯(lián)。例如,下面的程序片斷指示系統(tǒng)只要利用一個(gè)定制的URL訪問名為SomeServletName 的servlet或JSP頁面,就運(yùn)行名為Reporter的過濾器。
Reporter
SomeServletName
其次,可利用filter-name和url-pattern子元素將過濾器與一組servlet、JSP頁面或靜態(tài)內(nèi)容相關(guān)聯(lián)。例如,相面的程序片段指示系統(tǒng)只要訪問Web應(yīng)用中的任意URL,就運(yùn)行名為Reporter的過濾器。
Reporter
/*
例如,程序清單5-12給出了將ReportFilter過濾器與名為PageName的servlet相關(guān)聯(lián)的web.xml文件的一部分。名字 PageName依次又與一個(gè)名為TestPage.jsp的JSP頁面以及以模式http: //host/webAppPrefix/UrlTest2/ 開頭的URL相關(guān)聯(lián)。TestPage.jsp的源代碼已經(jīng)JSP頁面命名的談?wù)撛谇懊娴?節(jié)"分配名稱和定制的URL"中給出。事實(shí)上,程序清單5- 12中的servlet和servlet-name項(xiàng)從該節(jié)原封不動(dòng)地拿過來的。給定這些web.xml項(xiàng),可看到下面的標(biāo)準(zhǔn)輸出形式的調(diào)試報(bào)告(換行是為了容易閱讀)。
audit.irs.gov tried to access
http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html
on Tue Dec 25 13:12:29 EDT 2001.
程序清單5-12 Web.xml(說明filter用法的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
Reporter
moresevlets.ReportFilter
Reporter
PageName
PageName
/RealPage.jsp
PageName
/UrlTest2/*
7 指定歡迎頁
假如用戶提供了一個(gè)像http: //host/webAppPrefix/directoryName/ 這樣的包含一個(gè)目錄名但沒有包含文件名的URL,會(huì)發(fā)生什么事情呢?用戶能得到一個(gè)目錄表?一個(gè)錯(cuò)誤?還是標(biāo)準(zhǔn)文件的內(nèi)容?如果得到標(biāo)準(zhǔn)文件內(nèi)容,是 index.html、index.jsp、default.html、default.htm或別的什么東西呢?
Welcome-file-list 元素及其輔助的welcome-file元素解決了這個(gè)模糊的問題。例如,下面的web.xml項(xiàng)指出,如果一個(gè)URL給出一個(gè)目錄名但未給出文件名,服務(wù)器應(yīng)該首先試用index.jsp,然后再試用index.html。如果兩者都沒有找到,則結(jié)果有賴于所用的服務(wù)器(如一個(gè)目錄列表)。
index.jsp
index.html
雖然許多服務(wù)器缺省遵循這種行為,但不一定必須這樣。因此,明確地使用welcom-file-list保證可移植性是一種良好的習(xí)慣。
8 指定處理錯(cuò)誤的頁面
現(xiàn)在我了解到,你在開發(fā)servlet和JSP頁面時(shí)從不會(huì)犯錯(cuò)誤,而且你的所有頁面是那樣的清晰,一般的程序員都不會(huì)被它們的搞糊涂。但是,是人總會(huì)犯錯(cuò)誤的,用戶可能會(huì)提供不合規(guī)定的參數(shù),使用不正確的URL或者不能提供必需的表單字段值。除此之外,其它開發(fā)人員可能不那么細(xì)心,他們應(yīng)該有些工具來克服自己的不足。
error-page元素就是用來克服這些問題的。它有兩個(gè)可能的子元素,分別是:error-code和exception- type。第一個(gè)子元素error-code指出在給定的HTTP錯(cuò)誤代碼出現(xiàn)時(shí)使用的URL。第二個(gè)子元素excpetion-type指出在出現(xiàn)某個(gè)給定的Java異常但未捕捉到時(shí)使用的URL。error-code和exception-type都利用location元素指出相應(yīng)的URL。此 URL必須以/開始。location所指出的位置處的頁面可通過查找HttpServletRequest對(duì)象的兩個(gè)專門的屬性來訪問關(guān)于錯(cuò)誤的信息,這兩個(gè)屬性分別是:javax.servlet.error.status_code和javax.servlet.error.message。
可回憶一下,在web.xml內(nèi)以正確的次序聲明web-app的子元素很重要。這里只要記住,error-page出現(xiàn)在web.xml文件的末尾附近,servlet、servlet-name和welcome-file-list之后即可。
8.1 error-code元素
為了更好地了解error-code元素的值,可考慮一下如果不正確地輸入文件名,大多數(shù)站點(diǎn)會(huì)作出什么反映。這樣做一般會(huì)出現(xiàn)一個(gè)404錯(cuò)誤信息,它表示不能找到該文件,但幾乎沒提供更多有用的信息。另一方面,可以試一下在www.microsoft.com、www.ibm.com 處或者特別是在www.bea.com 處輸出未知的文件名。這是會(huì)得出有用的消息,這些消息提供可選擇的位置,以便查找感興趣的頁面。提供這樣有用的錯(cuò)誤頁面對(duì)于Web應(yīng)用來說是很有價(jià)值得。事實(shí)上rm-error-page子元素)。由form-login-page給出的HTML表單必須具有一個(gè)j_security_check的 ACTION屬性、一個(gè)名為j_username的用戶名文本字段以及一個(gè)名為j_password的口令字段。
例如,程序清單5-19指示服務(wù)器使用基于表單的驗(yàn)證。Web應(yīng)用的頂層目錄中的一個(gè)名為login.jsp的頁面將收集用戶名和口令,并且失敗的登陸將由相同目錄中名為login-error.jsp的頁面報(bào)告。
程序清單5-19 web.xml(說明login-config的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
...
FORM
/login.jsp
/login-error.jsp
9.2 限制對(duì)Web資源的訪問
現(xiàn)在,可以指示服務(wù)器使用何種驗(yàn)證方法了。"了不起,"你說道,"除非我能指定一個(gè)來收到保護(hù)的 URL,否則沒有多大用處。"沒錯(cuò)。指出這些URL并說明他們應(yīng)該得到何種保護(hù)正是security-constriaint元素的用途。此元素在 web.xml中應(yīng)該出現(xiàn)在login-config的緊前面。它包含是個(gè)可能的子元素,分別是:web-resource-collection、 auth-constraint、user-data-constraint和display-name。下面各小節(jié)對(duì)它們進(jìn)行介紹。
l web-resource-collection
此元素確定應(yīng)該保護(hù)的資源。所有security-constraint元素都必須包含至少一個(gè)web-resource-collection項(xiàng)。此元素由一個(gè)給出任意標(biāo)識(shí)名稱的web-resource-name元素、一個(gè)確定應(yīng)該保護(hù)的URL的url-pattern元素、一個(gè)指出此保護(hù)所適用的 HTTP命令(GET、POST等,缺省為所有方法)的http-method元素和一個(gè)提供資料的可選description元素組成。例如,下面的 Web-resource-collection項(xiàng)(在security-constratint元素內(nèi))指出Web應(yīng)用的proprietary目錄中所有文檔應(yīng)該受到保護(hù)。
Proprietary
/propritary/*
重要的是應(yīng)該注意到,url-pattern僅適用于直接訪問這些資源的客戶機(jī)。特別是,它不適合于通過MVC體系結(jié)構(gòu)利用 RequestDispatcher來訪問的頁面,或者不適合于利用類似jsp:forward的手段來訪問的頁面。這種不勻稱如果利用得當(dāng)?shù)脑捄苡泻锰?。例如,servlet可利用MVC體系結(jié)構(gòu)查找數(shù)據(jù),把它放到bean中,發(fā)送請(qǐng)求到從bean中提取數(shù)據(jù)的JSP頁面并顯示它。我們希望保證決不直接訪問受保護(hù)的JSP頁面,而只是通過建立該頁面將使用的bean的servlet來訪問它。url-pattern和auth-contraint元素可通過聲明不允許任何用戶直接訪問JSP頁面來提供這種保證。但是,這種不勻稱的行為可能讓開發(fā)人員放松警惕,使他們偶然對(duì)應(yīng)受保護(hù)的資源提供不受限制的訪問。
l auth-constraint
盡管web-resource-collention元素質(zhì)出了哪些URL應(yīng)該受到保護(hù),但是auth-constraint元素卻指出哪些用戶應(yīng)該具有受保護(hù)資源的訪問權(quán)。此元素應(yīng)該包含一個(gè)或多個(gè)標(biāo)識(shí)具有訪問權(quán)限的用戶類別role- name元素,以及包含(可選)一個(gè)描述角色的description元素。例如,下面web.xml中的security-constraint元素部門規(guī)定只有指定為Administrator或Big Kahuna(或兩者)的用戶具有指定資源的訪問權(quán)。
...
administrator
kahuna
重要的是認(rèn)識(shí)到,到此為止,這個(gè)過程的可移植部分結(jié)束了。服務(wù)器怎樣確定哪些用戶處于任何角色以及它怎樣存放用戶的口令,完全有賴于具體的系統(tǒng)。
例如,Tomcat使用install_dir/conf/tomcat-users.xml將用戶名與角色名和口令相關(guān)聯(lián),正如下面例子中所示,它指出用戶joe(口令bigshot)和jane(口令enaj)屬于administrator和kahuna角色。
l user-data-constraint
這個(gè)可選的元素指出在訪問相關(guān)資源時(shí)使用任何傳輸層保護(hù)。它必須包含一個(gè)transport-guarantee子元素(合法值為NONE、 INTEGRAL或CONFIDENTIAL),并且可選地包含一個(gè)description元素。transport-guarantee為NONE值將對(duì)所用的通訊協(xié)議不加限制。INTEGRAL值表示數(shù)據(jù)必須以一種防止截取它的人閱讀它的方式傳送。雖然原理上(并且在未來的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之間可能會(huì)有差別,但在當(dāng)前實(shí)踐中,他們都只是簡(jiǎn)單地要求用SSL。例如,下面指示服務(wù)器只允許對(duì)相關(guān)資源做 HTTPS連接:
CONFIDENTIAL
l display-name
security-constraint的這個(gè)很少使用的子元素給予可能由GUI工具使用的安全約束項(xiàng)一個(gè)名稱。
9.3 分配角色名
迄今為止,討論已經(jīng)集中到完全由容器(服務(wù)器)處理的安全問題之上了。但servlet以及JSP頁面也能夠處理它們自己的安全問題。
例如,容器可能允許用戶從bigwig或bigcheese角色訪問一個(gè)顯示主管人員額外緊貼的頁面,但只允許bigwig用戶修改此頁面的參數(shù)。完成這種更細(xì)致的控制的一種常見方法是調(diào)用HttpServletRequset的isUserInRole方法,并據(jù)此修改訪問。
Servlet的 security-role-ref子元素提供出現(xiàn)在服務(wù)器專用口令文件中的安全角色名的一個(gè)別名。例如,假如編寫了一個(gè)調(diào)用 request.isUserInRole("boss")的servlet,但后來該servlet被用在了一個(gè)其口令文件調(diào)用角色manager而不是boss的服務(wù)器中。下面的程序段使該servlet能夠使用這兩個(gè)名稱中的任何一個(gè)。
boss
manager
也可以在web-app內(nèi)利用security-role元素提供將出現(xiàn)在role-name元素中的所有安全角色的一個(gè)全局列表。分別地生命角色使高級(jí)IDE容易處理安全信息。
10 控制會(huì)話超時(shí)
如果某個(gè)會(huì)話在一定的時(shí)間內(nèi)未被訪問,服務(wù)器可把它扔掉以節(jié)約內(nèi)存??衫肏ttpSession的setMaxInactiveInterval方法直接設(shè)置個(gè)別會(huì)話對(duì)象的超時(shí)值。如果不采用這種方法,則缺省的超時(shí)值由具體的服務(wù)器決定。但可利用session-config和session- timeout元素來給出一個(gè)適用于所有服務(wù)器的明確的超時(shí)值。超時(shí)值的單位為分鐘,因此,下面的例子設(shè)置缺省會(huì)話超時(shí)值為三個(gè)小時(shí)(180分鐘)。
180
11 Web應(yīng)用的文檔化
越來越多的開發(fā)環(huán)境開始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio(寫此文時(shí),已被Macromedia收購)以及IBM VisuaAge for Java等。
大量的web.xml元素不僅是為服務(wù)器設(shè)計(jì)的,而且還是為可視開發(fā)環(huán)境設(shè)計(jì)的。它們包括icon、display-name和discription等。
可回憶一下,在web.xml內(nèi)以適當(dāng)?shù)卮涡蚵暶鱳eb-app子元素很重要。不過,這里只要記住icon、display-name和description是web.xml的web-app元素內(nèi)的前三個(gè)合法元素即可。
l icon
icon元素指出GUI工具可用來代表Web應(yīng)用的一個(gè)和兩個(gè)圖像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG圖像,用large-icon元素指定一幅32 x 32的圖像。下面舉一個(gè)例子:
/images/small-book.gif
/images/tome.jpg
l display-name
display-name元素提供GUI工具可能會(huì)用來標(biāo)記此Web應(yīng)用的一個(gè)名稱。下面是個(gè)例子。
Rare Books
l description
description元素提供解釋性文本,如下所示:
This Web application represents the store developed for
rare-books.com, an online bookstore specializing in rare
and limited-edition books.
12 關(guān)聯(lián)文件與MIME類型
服務(wù)器一般都具有一種讓W(xué)eb站點(diǎn)管理員將文件擴(kuò)展名與媒體相關(guān)聯(lián)的方法。例如,將會(huì)自動(dòng)給予名為mom.jpg的文件一個(gè)image/jpeg的MIME 類型。但是,假如你的Web應(yīng)用具有幾個(gè)不尋常的文件,你希望保證它們?cè)诎l(fā)送到客戶機(jī)時(shí)分配為某種MIME類型。mime-mapping元素(具有 extension和mime-type子元素)可提供這種保證。例如,下面的代碼指示服務(wù)器將application/x-fubar的MIME類型分配給所有以.foo結(jié)尾的文件。
foo
application/x-fubar
或許,你的Web應(yīng)用希望重載(override)標(biāo)準(zhǔn)的映射。例如,下面的代碼將告訴服務(wù)器在發(fā)送到客戶機(jī)時(shí)指定.ps文件作為純文本(text/plain)而不是作為PostScript(application/postscript)。
ps
application/postscript
13 定位TLD
JSP taglib元素具有一個(gè)必要的uri屬性,它給出一個(gè)TLD(Tag Library Descriptor)文件相對(duì)于Web應(yīng)用的根的位置。TLD文件的實(shí)際名稱在發(fā)布新的標(biāo)簽庫版本時(shí)可能會(huì)改變,但我們希望避免更改所有現(xiàn)有JSP頁面。此外,可能還希望使用保持taglib元素的簡(jiǎn)練性的一個(gè)簡(jiǎn)短的uri。這就是部署描述符文件的taglib元素派用場(chǎng)的所在了。Taglib包含兩個(gè)子元素:taglib-uri和taglib-location。taglib-uri元素應(yīng)該與用于JSP taglib元素的uri屬性的東西相匹配。Taglib-location元素給出TLD文件的實(shí)際位置。例如,假如你將文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中?,F(xiàn)在,假如web.xml在web-app元素內(nèi)包含下列內(nèi)容。
/charts.tld
/WEB-INF/tlds/chart-tags-1.3beta.tld
給出這個(gè)說明后,JSP頁面可通過下面的簡(jiǎn)化形式使用標(biāo)簽庫。
<%@ taglib uri="/charts.tld" prefix="somePrefix" %>
14 指定應(yīng)用事件監(jiān)聽程序
應(yīng)用事件監(jiān)聽器程序是建立或修改servlet環(huán)境或會(huì)話對(duì)象時(shí)通知的類。它們是servlet規(guī)范的版本2.3中的新內(nèi)容。這里只簡(jiǎn)單地說明用來向Web應(yīng)用注冊(cè)一個(gè)監(jiān)聽程序的web.xml的用法。
注冊(cè)一個(gè)監(jiān)聽程序涉及在web.xml的web-app元素內(nèi)放置一個(gè)listener元素。在listener元素內(nèi),listener-class元素列出監(jiān)聽程序的完整的限定類名,如下所示:
package.ListenerClass
雖然listener元素的結(jié)構(gòu)很簡(jiǎn)單,但請(qǐng)不要忘記,必須正確地給出web-app元素內(nèi)的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因?yàn)閼?yīng)用生存期監(jiān)聽程序是serlvet規(guī)范的2.3版本中的新內(nèi)容,所以必須使用 web.xml DTD的2.3版本,而不是2.2版本。
例如,程序清單5-20給出一個(gè)名為ContextReporter的簡(jiǎn)單的監(jiān)聽程序,只要Web應(yīng)用的Servlet-Context建立(如裝載Web應(yīng)用)或消除(如服務(wù)器關(guān)閉)時(shí),它就在標(biāo)準(zhǔn)輸出上顯示一條消息。程序清單5-21給出此監(jiān)聽程序注冊(cè)所需要的web.xml文件的一部分。
程序清單5-20 ContextReporterjava
package moreservlets;
import javax.servlet.*;
import java.util.*;
/** Simple listener that prints a report on the standard output
* when the ServletContext is created or destroyed.
*
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* ? 2002 Marty Hall; may be freely used or adapted.
*/
public class ContextReporter implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("Context created on " +
new Date() + ".");
}
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Context destroyed on " +
new Date() + ".");
}
}
程序清單5-21 web.xml(聲明一個(gè)監(jiān)聽程序的摘錄)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
…
package.ListenerClass
...
15 J2EE元素
本節(jié)描述用作J2EE環(huán)境組成部分的Web應(yīng)用的web.xml元素。這里將提供一個(gè)簡(jiǎn)明的介紹,詳細(xì)內(nèi)容可以參閱http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3規(guī)范的第5章。
l distributable
distributable 元素指出,Web應(yīng)用是以這樣的方式編程的:即,支持集群的服務(wù)器可安全地在多個(gè)服務(wù)器上分布Web應(yīng)用。例如,一個(gè)可分布的應(yīng)用必須只使用 Serializable對(duì)象作為其HttpSession對(duì)象的屬性,而且必須避免用實(shí)例變量(字段)來實(shí)現(xiàn)持續(xù)性。distributable元素直接出現(xiàn)在discription元素之后,并且不包含子元素或數(shù)據(jù),它只是一個(gè)如下的標(biāo)志。
l resource-env-ref
resource -env-ref元素聲明一個(gè)與某個(gè)資源有關(guān)的管理對(duì)象。此元素由一個(gè)可選的description元素、一個(gè)resource-env-ref- name元素(一個(gè)相對(duì)于java:comp/env環(huán)境的JNDI名)以及一個(gè)resource-env-type元素(指定資源類型的完全限定的類),如下所示:
jms/StockQueue
javax.jms.Queue
l env-entry
env -entry元素聲明Web應(yīng)用的環(huán)境項(xiàng)。它由一個(gè)可選的description元素、一個(gè)env-entry-name元素(一個(gè)相對(duì)于java: comp/env環(huán)境JNDI名)、一個(gè)env-entry-value元素(項(xiàng)值)以及一個(gè)env-entry-type元素(java.lang程序包中一個(gè)類型的完全限定類名,java.lang.Boolean、java.lang.String等)組成。下面是一個(gè)例子:
minAmout
100.00
minAmout
l ejb-ref
ejb -ref元素聲明對(duì)一個(gè)EJB的主目錄的應(yīng)用。它由一個(gè)可選的description元素、一個(gè)ejb-ref-name元素(相對(duì)于java: comp/env的EJB應(yīng)用)、一個(gè)ejb-ref-type元素(bean的類型,Entity或Session)、一個(gè)home元素(bean的主目錄接口的完全限定名)、一個(gè)remote元素(bean的遠(yuǎn)程接口的完全限定名)以及一個(gè)可選的ejb-link元素(當(dāng)前bean鏈接的另一個(gè) bean的名稱)組成。
l ejb-local-ref
ejb-local-ref元素聲明一個(gè)EJB的本地主目錄的引用。除了用local-home代替home外,此元素具有與ejb-ref元素相同的屬性并以相同的方式使用。
很多的時(shí)侯,做Oracle DBA的我們,當(dāng)應(yīng)用管理員向我們通告現(xiàn)在應(yīng)用很慢、數(shù)據(jù)庫很慢的時(shí)侯,我們到數(shù)據(jù)庫時(shí)做幾個(gè)示例的Select也發(fā)現(xiàn)同樣的問題時(shí),有些時(shí)侯我們會(huì)無從下手,因?yàn)槲覀冋J(rèn)為數(shù)據(jù)庫的各種命種率都是滿足Oracle文檔的建議。實(shí)際上如今的優(yōu)化己經(jīng)向優(yōu)化等待(waits)轉(zhuǎn)型了,實(shí)際中性能優(yōu)化最根本的出現(xiàn)點(diǎn)也都集中在IO,這是影響性能最主要的方面,由系統(tǒng)中的等待去發(fā)現(xiàn)Oracle庫中的不足、操作系統(tǒng)某些資源利用的不合理是一個(gè)比較好的辦法,下面把我的一點(diǎn)實(shí)踐經(jīng)驗(yàn)與大家分享一下,本文測(cè)重于Unix環(huán)境。
一、通過操作系統(tǒng)的一些工具檢查系統(tǒng)的狀態(tài),比如CPU、內(nèi)存、交換、磁盤的利用率,根據(jù)經(jīng)驗(yàn)或與系統(tǒng)正常時(shí)的狀態(tài)相比對(duì),有時(shí)系統(tǒng)表面上看起來看空閑這也可能不是一個(gè)正常的狀態(tài),因?yàn)閏pu可能正等待IO的完成。除此之外我們還應(yīng)觀注那些占用系統(tǒng)資源(cpu、內(nèi)存)的進(jìn)程。
1、如何檢查操作系統(tǒng)是否存在IO的問題?使用的工具有sar,這是一個(gè)比較通用的工具。
Rp1#Sar -u 2 10
即每隔2秒檢察一次,共執(zhí)行20次,當(dāng)然這些都由你決定了。
示例返回:
HP-UX hpn2 B.11.00 U 9000/800 08/05/03
18:26:32 %usr %sys %wio %idle
18:26:34 80 9 12 0
18:26:36 78 11 11 0
18:26:38 78 9 13 1
18:26:40 81 10 9 1
18:26:42 75 10 14 0
18:26:44 76 8 15 0
18:26:46 80 9 10 1
18:26:48 78 11 11 0
18:26:50 79 10 10 0
18:26:52 81 10 9 0
Average 79 10 11 0
其中的%usr指的是用戶進(jìn)程使用的cpu資源的百分比,%sys指的是系統(tǒng)資源使用cpu資源的百分比,%wio指的是等待io完成的百分比,這是值得我們觀注的一項(xiàng),%idle即空閑的百分比。如果wio列的值很大,如在35%以上,說明你的系統(tǒng)的IO存在瓶頸,你的CPU花費(fèi)了很大的時(shí)間去等待IO的完成。Idle很小說明系統(tǒng)CPU很忙。像我的這個(gè)示例,可以看到wio平均值為11說明io沒什么特別的問題,而我的idle值為零,說明我的cpu已經(jīng)滿負(fù)荷運(yùn)行了。
當(dāng)你的系統(tǒng)存在IO的問題,可以從以下幾個(gè)方面解決
*聯(lián)系相應(yīng)的操作系統(tǒng)的技術(shù)支持對(duì)這方面進(jìn)行優(yōu)化,比如hp-ux在劃定卷組時(shí)的條帶化等方面。
*查找Oracle中不合理的sql語句,對(duì)其進(jìn)行優(yōu)化
*對(duì)Oracle中訪問量頻繁的表除合理建索引外,再就是把這些表分表空間存放以免訪問上產(chǎn)生熱點(diǎn),再有就是對(duì)表合理分區(qū)。
2、關(guān)注一下內(nèi)存。
常用的工具便是vmstat,對(duì)于hp-unix來說可以用glance,Aix來說可以用topas,當(dāng)你發(fā)現(xiàn)vmstat中pi列非零,memory中的free列的值很小,glance,topas中內(nèi)存的利用率多于80%時(shí),這時(shí)說明你的內(nèi)存方面應(yīng)該調(diào)節(jié)一下了,方法大體有以下幾項(xiàng)。
*?jiǎng)澖oOracle使用的內(nèi)存不要超過系統(tǒng)內(nèi)存的1/2,一般保在系統(tǒng)內(nèi)存的40%為益。
為系統(tǒng)增加內(nèi)存
*如果你的連接特別多,可以使用MTS的方式
*打全補(bǔ)丁,防止內(nèi)存漏洞。
3、如何找到點(diǎn)用系用資源特別大的Oracle的session及其執(zhí)行的語句。
Hp-unix可以用glance,top
IBM AIX可以用topas
此外可以使用ps的命令。
通過這些程序我們可以找到點(diǎn)用系統(tǒng)資源特別大的這些進(jìn)程的進(jìn)程號(hào),我們就可以通過以下的sql語句發(fā)現(xiàn)這個(gè)pid正在執(zhí)行哪個(gè)sql,這個(gè)sql最好在pl/sql developer,toad等軟件中執(zhí)行, 把<>中的spid換成你的spid就可以了。
SELECT a.username,
a.machine,
a.program,
a.sid,
a.serial#,
a.status,
c.piece,
c.sql_text
FROM v$session a,
v$process b,
v$sqltext c
WHERE b.spid=
AND b.addr=a.paddr
AND a.sql_address=c.address(+)
ORDER BY c.piece
我們就可以把得到的這個(gè)sql分析一下,看一下它的執(zhí)行計(jì)劃是否走索引,對(duì)其優(yōu)化避免全表掃描,以減少IO等待,從而加快語句的執(zhí)行速度。
提示:我在做優(yōu)化sql時(shí),經(jīng)常碰到使用in的語句,這時(shí)我們一定要用exists把它給換掉,因?yàn)镺racle在處理In時(shí)是按Or的方式做的,即使使用了索引也會(huì)很慢。
比如:
SELECT col1,col2,col3 FROM table1 a
WHERE a.col1 not in (SELECT col1 FROM table2)
可以換成:
SELECT col1,col2,col3 FROM table1 a
WHERE not exists
(SELECT 'x' FROM table2 b
WHERE a.col1=b.col1)
4、另一個(gè)有用的腳本:查找前十條性能差的sql.
SELECT * FROM
(
SELECT PARSING_USER_ID
EXECUTIONS,
SORTS,
COMMAND_TYPE,
DISK_READS,
sql_text
FROM v$sqlarea
ORDER BY disk_reads DESC
)
WHERE ROWNUM<10 ;
二、迅速發(fā)現(xiàn)Oracle Server的性能問題的成因,我們可以求助于v$session_wait這個(gè)視圖,看系統(tǒng)的這些session在等什么,使用了多少的IO。以下是我提供的參考腳本:
腳本說明:查看占io較大的正在運(yùn)行的session
SELECT se.sid,
se.serial#,
pr.SPID,
se.username,
se.status,
se.terminal,
se.program,
se.MODULE,
se.sql_address,
st.event,
st.p1text,
si.physical_reads,
si.block_changes
FROM v$session se,
v$session_wait st,
v$sess_io si,
v$process pr
WHERE st.sid=se.sid
AND st.sid=si.sid
AND se.PADDR=pr.ADDR
AND se.sid>6
AND st.wait_time=0
AND st.event NOT LIKE '%SQL%'
ORDER BY physical_reads DESC
對(duì)檢索出的結(jié)果的幾點(diǎn)說明:
1、我是按每個(gè)正在等待的session已經(jīng)發(fā)生的物理讀排的序,因?yàn)樗c實(shí)際的IO相關(guān)。
2、你可以看一下這些等待的進(jìn)程都在忙什么,語句是否合理?
Select sql_address from v$session where sid= ;
Select * from v$sqltext where address= ;
執(zhí)行以上兩個(gè)語句便可以得到這個(gè)session的語句。
你也以用alter system kill session 'sid,serial#';把這個(gè)session殺掉。
3、應(yīng)觀注一下event這列,這是我們調(diào)優(yōu)的關(guān)鍵一列,下面對(duì)常出現(xiàn)的event做以簡(jiǎn)要的說明:
a、buffer busy waits,free buffer waits這兩個(gè)參數(shù)所標(biāo)識(shí)是dbwr是否夠用的問題,與IO很大相關(guān)的,當(dāng)v$session_wait中的free buffer wait的條目很小或沒有的時(shí)侯,說明你的系統(tǒng)的dbwr進(jìn)程決對(duì)夠用,不用調(diào)整;free buffer wait的條目很多,你的系統(tǒng)感覺起來一定很慢,這時(shí)說明你的dbwr已經(jīng)不夠用了,它產(chǎn)生的wio已經(jīng)成為你的數(shù)據(jù)庫性能的瓶頸,這時(shí)的解決辦法如下:
a.1增加寫進(jìn)程,同時(shí)要調(diào)整db_block_lru_latches參數(shù)
示例:修改或添加如下兩個(gè)參數(shù)
db_writer_processes=4
db_block_lru_latches=8
a、2開異步IO,IBM這方面簡(jiǎn)單得多,hp則麻煩一些,可以與Hp工程師聯(lián)系。
b、db file sequential read,指的是順序讀,即全表掃描,這也是我們應(yīng)該盡量減少的部分,解決方法就是使用索引、sql調(diào)優(yōu),同時(shí)可以增大db_file_multiblock_read_count這個(gè)參數(shù)。
c、db file scattered read,這個(gè)參數(shù)指的是通過索引來讀取,同樣可以通過增加db_file_multiblock_read_count這個(gè)參數(shù)來提高性能。
d、latch free,與栓相關(guān)的了,需要專門調(diào)節(jié)。
e、其他參數(shù)可以不特別觀注。
結(jié)篇:匆忙之中寫下了這篇文章,希望能拋磚引玉,能為你的Oracle調(diào)優(yōu)實(shí)踐帶來幫助。
任何事情都有它的源頭,要解決問題,也得從源頭開始,影響ORACLE性能的源頭非常多,主要包括如下方面:
數(shù)據(jù)庫的硬件配置:CPU、內(nèi)存、網(wǎng)絡(luò)條件
1. CPU:在任何機(jī)器中CPU的數(shù)據(jù)處理能力往往是衡量計(jì)算機(jī)性能的一個(gè)標(biāo)志,并且ORACLE是一個(gè)提供并行能力的數(shù)據(jù)庫系統(tǒng),在CPU方面的要求就更高了,如果運(yùn)行隊(duì)列數(shù)目超過了CPU處理的數(shù)目,性能就會(huì)下降,我們要解決的問題就是要適當(dāng)增加CPU的數(shù)量了,當(dāng)然我們還可以將需要許多資源的進(jìn)程KILL掉;
2. 內(nèi)存:衡量機(jī)器性能的另外一個(gè)指標(biāo)就是內(nèi)存的多少了,在ORACLE中內(nèi)存和我們?cè)诮〝?shù)據(jù)庫中的交換區(qū)進(jìn)行數(shù)據(jù)的交換,讀數(shù)據(jù)時(shí),磁盤I/O必須等待物理I/O操作完成,在出現(xiàn)ORACLE的內(nèi)存瓶頸時(shí),我們第一個(gè)要考慮的是增加內(nèi)存,由于I/O的響應(yīng)時(shí)間是影響ORACLE性能的主要參數(shù),我將在這方面進(jìn)行詳細(xì)的講解
3. 網(wǎng)絡(luò)條件:NET*SQL負(fù)責(zé)數(shù)據(jù)在網(wǎng)絡(luò)上的來往,大量的SQL會(huì)令網(wǎng)絡(luò)速度變慢。比如10M的網(wǎng)卡和100的網(wǎng)卡就對(duì)NET*SQL有非常明顯的影響,還有交換機(jī)、集線器等等網(wǎng)絡(luò)設(shè)備的性能對(duì)網(wǎng)絡(luò)的影響很明顯,建議在任何網(wǎng)絡(luò)中不要試圖用3個(gè)集線器來將網(wǎng)段互聯(lián)。
? OS參數(shù)的設(shè)置
下表給出了OS的參數(shù)設(shè)置及說明,DBA可以根據(jù)實(shí)際需要對(duì)這些參數(shù)進(jìn)行設(shè)置
內(nèi)核參數(shù)名 |
說明 |
bufpages |
對(duì)buffer空間不按靜態(tài)分配,采用動(dòng)態(tài)分配,使bufpages值隨nbuf一起對(duì)buffer空間進(jìn)行動(dòng)態(tài)分配。 |
create_fastlinks |
對(duì)HFS文件系統(tǒng)允許快速符號(hào)鏈接, |
dbc_max_pct |
加大最大動(dòng)態(tài)buffer空間所占物理內(nèi)存的百分比,以滿足應(yīng)用系統(tǒng)的讀寫命中率的需要。 |
dbc_min_pct |
設(shè)置最小動(dòng)態(tài)buffer空間所占物理內(nèi)存的百分比 |
desfree |
提高開始交換操作的最低空閑內(nèi)存下限,保障系統(tǒng)的穩(wěn)定性,防止出現(xiàn)不可預(yù)見的系統(tǒng)崩潰(Crash)。 |
fs_async |
允許進(jìn)行磁盤異步操作,提高CPU和磁盤的利用率 |
lotsfree |
提高系統(tǒng)解除換頁操作的空閑內(nèi)存的上限值,保證應(yīng)用程序有足夠的可用內(nèi)存空間。 |
maxdsiz |
針對(duì)系統(tǒng)數(shù)據(jù)量大的特點(diǎn),加大最大數(shù)據(jù)段的大小,保證應(yīng)用的需要。(32位) |
maxdsiz_64bit |
maximum process data segment size for 64_bit |
Maxssiz |
加大最大堆棧段的大小。(32_bit) |
maxssiz_64bit |
加大最大堆棧段的大?。?4_bit) |
Maxtsiz |
提高最大代碼段大小,滿足應(yīng)用要求 |
maxtsiz_64bit |
原值過大,應(yīng)調(diào)小 |
Minfree |
提高停止交換操作的自由內(nèi)存的上限 |
Shmem |
允許進(jìn)行內(nèi)存共享,以提高內(nèi)存的利用率。 |
Shmmax |
設(shè)置最大共享內(nèi)存段的大小,完全滿足目前的需要。 |
Timeslice |
由于系統(tǒng)的瓶頸主要反映在磁盤I/O上,因此 降低時(shí)間片的大小,一方面可避免因磁盤I/O不暢造成CPU的等待,從而提高了CPU的綜合利用率。另一方面減少了進(jìn)程的阻塞量。 |
unlockable_mem |
提高了不可鎖內(nèi)存的大小,使可用于換頁和交換的內(nèi)存空間擴(kuò)大,用以滿足系統(tǒng)對(duì)內(nèi)存管理的要求。 |
用戶SQL質(zhì)量
以上講的都是硬件方面的東西,在條件有限的條件下,我們可以調(diào)整應(yīng)用程序的SQL質(zhì)量:
1. 不要進(jìn)行全表掃描(Full Table Scan):全表掃描導(dǎo)致大量的I/O
2. 盡量建好和使用好索引:建索引也是有講究的,在建索引時(shí),也不是索引越多越好,當(dāng)一個(gè)表的索引達(dá)到4個(gè)以上時(shí),ORACLE的性能可能還是改善不了,因?yàn)镺LTP系統(tǒng)每表超過5個(gè)索引即會(huì)降低性能,而且在一個(gè)sql 中, Oracle 從不能使用超過 5個(gè)索引;當(dāng)我們用到GROUP BY和ORDER BY時(shí),ORACLE就會(huì)自動(dòng)對(duì)數(shù)據(jù)進(jìn)行排序,而ORACLE在INIT.ORA中決定了sort_area_size區(qū)的大小,當(dāng)排序不能在我們給定的排序區(qū)完成時(shí),ORACLE就會(huì)在磁盤中進(jìn)行排序,也就是我們講的臨時(shí)表空間中排序, 過多的磁盤排序?qū)?huì)令 free buffer waits 的值變高,而這個(gè)區(qū)間并不只是用于排序的,對(duì)于開發(fā)人員我提出如下忠告:
1)、select,update,delete 語句中的子查詢應(yīng)當(dāng)有規(guī)律地查找少于20%的表行.如果一個(gè)語句查找的行數(shù)超過總行數(shù)的20%,它將不能通過使用索引獲得性能上的提高.
2)、索引可能產(chǎn)生碎片,因?yàn)橛涗洀谋碇袆h除時(shí),相應(yīng)也從表的索引中刪除.表釋放的空間可以再用,而索引釋放的空間卻不能再用.頻繁進(jìn)行刪除操作的被索引的表,應(yīng)當(dāng)階段性地重建索引,以避免在索引中造成空間碎片,影響性能.在許可的條件下,也可以階段性地truncate表,truncate命令刪除表中所有記錄,也刪除索引碎片.
3)、在使用索引時(shí)一定要按索引對(duì)應(yīng)字段的順序進(jìn)行引用。
4)、用(+)比用NOT IN更有效率。
? 降低ORACLE的競(jìng)爭(zhēng):
先講幾個(gè)ORACLE的幾個(gè)參數(shù),這幾個(gè)參數(shù)關(guān)系到ORACLE的競(jìng)爭(zhēng):
1)、freelists 和 freelist 組:他們負(fù)責(zé)ORACLE的處理表和索引的空間管理;
2)、pctfree 及 pctused:該參數(shù)決定了freelists 和 freelist 組的行為,pctfree 和pctused 參數(shù)的唯一目的就是為了控制塊如何在 freelists 中進(jìn)出
設(shè)置好pctfree 及 pctused對(duì)塊在freelists的移走和讀取很重要。
? 其他參數(shù)的設(shè)置
1)、包括SGA區(qū)(系統(tǒng)全局區(qū)):系統(tǒng)全局區(qū)(SGA)是一個(gè)分配給Oracle 的包含一個(gè) Oracle 實(shí)例的數(shù)據(jù)庫的控制信息內(nèi)存段。
主要包括數(shù)據(jù)庫高速緩存(the database buffer cache),
重演日志緩存(the redo log buffer),
共享池(the shared pool),
數(shù)據(jù)字典緩存(the data dictionary cache)以及其它各方面的信息
2)、db_block_buffers(數(shù)據(jù)高速緩沖區(qū))訪問過的數(shù)據(jù)都放在這一片內(nèi)存區(qū)域,該參數(shù)越大,Oracle在內(nèi)存中找到相同數(shù)據(jù)的可能性就越大,也即加快了查詢速度。
3)、share_pool_size (SQL共享緩沖池):該參數(shù)是庫高速緩存和數(shù)據(jù)字典的高速緩存。
4)、Log_buffer (重演日志緩沖區(qū))
5)、sort_area_size(排序區(qū))
6)、processes (同時(shí)連接的進(jìn)程數(shù))
7)、db_block_size (數(shù)據(jù)庫塊大?。篛racle默認(rèn)塊為2KB,太小了,因?yàn)槿绻覀冇幸粋€(gè)8KB的數(shù)據(jù),則2KB塊的數(shù)據(jù)庫要讀4次盤,才能讀完,而8KB塊的數(shù)據(jù)庫只要1次就讀完了,大大減少了I/O操作。數(shù)據(jù)庫安裝完成后,就不能再改變db_block_size的值了,只能重新建立數(shù)據(jù)庫并且建庫時(shí),要選擇手工安裝數(shù)據(jù)庫。
8)、open_links (同時(shí)打開的鏈接數(shù))
9)、dml_locks
10)、open_cursors (打開光標(biāo)數(shù))
11)、dbwr_io_slaves (后臺(tái)寫進(jìn)程數(shù))
摘要: web.xml 配置
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"><web-app>...
閱讀全文
Bruce Tate , 總裁, J2Life, LLC
輕量級(jí)容器可以動(dòng)態(tài)地使系統(tǒng)主要組件之間的耦合變松散。不同的容器包含相同的設(shè)計(jì)模式,但卻具有根本不同的哲學(xué)。本文幫助您在下列三種輕量級(jí)容器之間作出最佳選擇:Spring Framework、HiveMind 和 PicoContainer。
2002 年在科羅拉多的一次旅行中,我完美地感受了阿肯色河。在三段不同的漂流中,這條河展示了令人驚異的多樣性。柔美的布朗峽谷有著開闊的急流,翻滾著巨大的波浪。Royal Gorge 別具特色的懸崖峭壁引導(dǎo)著巨大而筆直的峽谷之下的水力,在這條直線上發(fā)生一點(diǎn)小閃失都會(huì)受到長(zhǎng)途游泳的懲罰。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é)??偠灾糠N容器的作者都忠于他們的哲學(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 注入。
- 在靈活性和簡(jiǎn)單性之間,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 的文檔工具,友好簡(jiǎn)明的 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 具有最簡(jiǎn)單的編程模型。要查看 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)。(記?。篐iveMind 強(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 文件中
然后,其他應(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. 使用攔截器添加功能
PetClinic 應(yīng)用程序 (Spring)
Spring 處理事情的方法有些不同。因?yàn)?Spring 框架不帶有簡(jiǎn)單的應(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 配置文件
該上下文中有兩個(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ì)比較,比如市場(chǎng)份額、整體質(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)歷簡(jiǎn)直太美好了。Spring 貢獻(xiàn)者、創(chuàng)始人和用戶都以杰出的內(nèi)容填滿了留言板。
HiveMind 框架是一個(gè) Apache Jakarta 項(xiàng)目,所以有著扎實(shí)的基礎(chǔ)。它有一個(gè)正在成長(zhǎng)的萌芽社區(qū)。該框架的創(chuàng)始人 Howard Lewis Ship 是獨(dú)立顧問、優(yōu)秀導(dǎo)師和不屈不撓的提倡者。但是,要利用 HiveMind 的質(zhì)量幫助或者查找其 Web 站點(diǎn)之外的內(nèi)容仍然十分困難。盡管如此,它的在線幫助似乎不錯(cuò),而且社區(qū)似乎正在成長(zhǎng)。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 變得簡(jiǎn)單易用的特性而自豪,比如行準(zhǔn)確的錯(cuò)誤報(bào)告;友好簡(jiǎn)明的 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 不嘗試參與競(jìng)爭(zhēng)。相反,它與 Spring 的服務(wù)兼容。PicoContainer 不構(gòu)建而且也不嘗試構(gòu)建附加物,而是選擇讓開放源碼項(xiàng)目為其提供服務(wù)。到目前為止,它的效果不太好。
哪一個(gè)最好?
目前,只有一個(gè)真正的答案。HiveMind 具有有趣的創(chuàng)新,PicoContainer 具有易于使用的模型(理論上),但社區(qū)似乎已經(jīng)投票選擇了 Spring Framework。隨著時(shí)間的推移,新的容器可能會(huì)成長(zhǎng),HiveMind 可能不斷獲得市場(chǎng)份額,但目前,Spring 是您的最佳選擇。
如果您愿意冒一些險(xiǎn),而使用不太成熟或不太流行的容器,您可能決定實(shí)現(xiàn) HiveMind(如果需要模塊級(jí)別的配置)或 PicoContainer(如果想要微小的容器)。如果需要許多膠水代碼來集成持久引擎、事務(wù)處理策略和安全性等方面,Spring 具有最完整的組件堆。但請(qǐng)記?。耗梢栽?HiveMind 容器中使用 Spring 組件。
參考資料
學(xué)習(xí)
原文:
http://www-128.ibm.com/developerworks/cn/opensource/os-lightweight4/
在JSP中我們經(jīng)常要調(diào)用服務(wù)器端的一些dos命令,已達(dá)到一些特殊的效果,但同時(shí)調(diào)用服務(wù)器端的dos命令也存在著一些安全隱患,因此需要慎重使用。
以下以一個(gè)例子來說明用jsp執(zhí)行dos的過程,比如在服務(wù)器端每天都會(huì)自動(dòng)生成一個(gè)目錄(目錄名稱為當(dāng)天的日期),再此目錄下會(huì)生成一些當(dāng)天的新聞文件,管理員會(huì)把這些文件幾個(gè)月作一次備份,備份完后在把這些文件刪除。
如果在服務(wù)器上,我們可以在dos下直接執(zhí)行c:\j2sdk\jar cf d:\bak\200502.jar d:\news\20050101 命令, 然后再把20050101目錄刪除即可。
在JSP中我們應(yīng)當(dāng)這么來寫
<%
//執(zhí)行dos命令
String commandstr = "c:/j2sdk/jar cf d:/bak/200502.jar d:/news/20050101";
Process p ;
try {
p = Runtime.getRuntime().exec(commandstr);
//等待剛剛執(zhí)行的命令的結(jié)束
while (true){
if(p.waitFor() == 0) break;
}
} catch (Exception e) {
out.println(e.toString());
}
//刪除已經(jīng)打包的文件及其目錄
File f = new File("d:/news/20020101");
String[] allFiles = f.list();
for (int i = 0; i < allFiles.length; i++) {
File delF = new File("d:/news/20050101/"+allFiles[i]);
delF.delete();
}
File delD = new File("d:/news/20050101");
delD.delete();
%>
在jsp中以下代碼必須執(zhí)行,如果沒有該代碼,則由于刪除文件的速度快于打包的速度,因此當(dāng)壓縮包還沒有打包完成,一些文件已經(jīng)被刪除,加入下面的代碼,會(huì)在此一直做循環(huán),一直p.waitFor()(這個(gè)方法的說明是:等待子進(jìn)程的結(jié)束,如果已經(jīng)結(jié)束,一般返回0)返回0為止才會(huì)接著執(zhí)行后面的代碼
while (true){
if(p.waitFor() == 0) break;
}
先還是看一段程序后,再一一講解其內(nèi)容吧
public class ReadMail
{
//初始化主機(jī)
String host=”smtp.163.com”;
String nuserName=”郵箱的用戶名”;
String pwd=”用戶密碼”;
Session session;
Public void readMail()
{
Properties props=new Properties();
props.put(“mail.transport.protocol”,”smtp”);
props.put(“mail.smtp.host”,””+host+””);
props.put(“mail.smtp.port”,”25”);
session=Session.getDefaultInstance(props);
//獲取Store對(duì)象,使用pop3協(xié)議也可以使用IMAP
Stroe store=session.getStore(“pop3”);
//連接到郵件服務(wù)器
store.connect(host,username,password);
//獲取該用Floder對(duì),并以只讀方式打開
Folder folder=store.getFolder(“INBOX”);
Folder.open(Folder.READ_ONLY);
//檢索所有郵件,按需填充
Message msg[]=folder.getMessage();
//遍歷每一個(gè)郵件
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
For(int i=0,n=msg.length;I<n;I++)
{
//打印每個(gè)郵件的發(fā)件人和主題
System.out.println(I+”:”+msg[i].getFrom()[0]+”\t”+msg[i].getSubject());
//顯示消息內(nèi)容
msg[i].writeTo(System.out);
}
floder.close(false);
store.close();
}
}
現(xiàn)在對(duì)程序一一講解吧!
Store是一個(gè)抽象類,它模擬了消息存儲(chǔ)器(或稱為消息數(shù)據(jù)庫)及其內(nèi)部目錄(Folder)訪問協(xié)議,以存儲(chǔ)和讀取消息,由其子類提供具體實(shí)現(xiàn)。客戶程序可以通過獲取一個(gè)Store對(duì)象來訪問消息存儲(chǔ)器,以絕大多數(shù)的存儲(chǔ)器要求用戶在訪問前提供認(rèn)證信息,connect方法執(zhí)行了該認(rèn)證過程。與Transport類似,也可以指定Store使用協(xié)議。郵件是讀取郵件所以用pop3協(xié)議來讀取。
具體如:Store store=new Store(“pop3”);
然后認(rèn)證:store.connect(host,username,pwd)
javax.mail.Folder類,它是一個(gè)抽象類,用于分級(jí)組織郵件,其子類提供針對(duì)具本協(xié)議的實(shí)現(xiàn)。存儲(chǔ)在目錄內(nèi)的消息被順序計(jì)數(shù)(從1開始到消息總數(shù)),該順序被稱為郵箱順序,郵件順序的改變消息的序列號(hào),這種情況僅發(fā)生在客戶程序調(diào)用Expunge方法擦除目錄內(nèi)設(shè)置了Flags.Flag.DELETED標(biāo)志位的消息時(shí)。執(zhí)行擦除操作后,目錄內(nèi)消息將重新編號(hào)??蛻舫绦蚩梢酝ㄟ^消息序列號(hào)和直接通過相應(yīng)的Message對(duì)象引用目錄中的對(duì)象,由于消息序列號(hào)會(huì)在會(huì)話中很可能會(huì)改變,因此應(yīng)盡可能保存Message對(duì)象來引用對(duì)象。
連接stroe之后,接一來就可以獲取一個(gè)文件夾(Folder)。該文件夾必須先使用open()方法打開,然后才能讀取里面的消息。
Folder folder=store.getDefaultFolder();
//或Folder folder=store.getFolder(“inbox”);
folder.open(Folder.READ_WRITE);
Message message[]=folder.getMessages();
Open()方法指定了要打開的文件及打開方試(如Folder.READ_WRITE)。Inbox是pop3惟一可以使用的文件夾。如果使用IMAP,還可以使用其它的文件夾。讀取了Message之后,就可以用getContent()獲得內(nèi)容,或者用writeTo()將內(nèi)容寫入輸出流。GetContent()方法只能得到消息內(nèi)容,而writeTo()輸出卻包含消息頭.
如下兩種方試
System.out.println(((MimeMessage)msg).getContent());
Msg.writeTo(System.out);
讀完郵件后要關(guān)閉與Folder和Store的連接
folder.close(false);
stroe.close();