千里冰封
          JAVA 濃香四溢
          posts - 151,comments - 2801,trackbacks - 0
          本文面向的觀眾是對(duì)J2EE技術(shù)有興趣的入門者。

              Java語言

              Java語言最早被稱為Oak,它是為了實(shí)現(xiàn)嵌入式的消費(fèi)類電子產(chǎn)品應(yīng)用而產(chǎn)生的,它的作者是James Gosling.Ed Frank, Patrick Naughton, Jonathan Payne, Chris Warth在隨后的幾年時(shí)間中為Java語言加入了大量的特性,并把Java語言的目標(biāo)做了一個(gè)重新的定位,定位于適合Internet的語言。

              Java語言是一種多用途的語言、并發(fā)的語言、以類為基礎(chǔ),面向?qū)ο蟮恼Z言。它的設(shè)計(jì)盡可能的做到和操作系統(tǒng)是無關(guān)的,也就是Java所宣傳的那句話:“一次編寫,到處運(yùn)行。”Java的設(shè)計(jì)參考了C和C++語言,因此熟悉C和C++的程序員對(duì)Java語言上手很快,而Java設(shè)計(jì)的原則是能夠利用Java語言快捷的編寫應(yīng)用,所以我們可以發(fā)現(xiàn),在Java語言中,并沒有那些C和C++中的復(fù)雜的機(jī)制。最明顯的就是C中被大量使用的指針,由于它的隨意性,被Java以引用來代替了。而C++中的操作符重載、模板、泛型的特性也因?yàn)槭褂帽容^復(fù)雜,Java也不予采用。但是目前Java仍然不斷的推出新的特性,以滿足應(yīng)用的發(fā)展。例如在新推出的JDK1.4中,Java語言就能夠支持Assertment機(jī)制和Perl語言中最有用的正則表達(dá)式機(jī)制。

              Java語言主要由以下五種元素組成:標(biāo)識(shí)符、關(guān)鍵字、文字、運(yùn)算符和分隔符。這五種元素有著不同的語法含義和組成規(guī)則,它們互相配合,共同完成Java語言的語意表達(dá)。

              1:標(biāo)識(shí)符。變量,類和方法都需要一定的名稱,我們將這種名稱叫做標(biāo)識(shí)符。

              2:關(guān)鍵字。關(guān)鍵字是Java語言本身使用的標(biāo)識(shí)符,它有其特定的語法含義。所有的Java關(guān)鍵字將不能被用作標(biāo)識(shí)符。

              3:數(shù)據(jù)類型。Java有著不同的數(shù)據(jù)類型。比較值得一提的是字符串?dāng)?shù)據(jù)類型,字符串?dāng)?shù)據(jù)類型是用一對(duì)雙引號(hào)括起來的字符序列,字符串?dāng)?shù)據(jù)實(shí)際上是由String類所實(shí)現(xiàn),而不是C語言中所用的字符數(shù)組。每一個(gè)字符串?dāng)?shù)據(jù)將產(chǎn)生一個(gè)String類的新的實(shí)例,用戶不必對(duì)字符串與類這個(gè)概念發(fā)生關(guān)系而感到擔(dān)心,由于類的特性,你不必?fù)?dān)心如何去實(shí)現(xiàn)它們,它們會(huì)自己照顧好自己,需要說明的是字符串在Java里作為類只是出于安全的考慮。

              4:運(yùn)算符。任何語言都有自己的運(yùn)算符,Java語言也不例外,如+、-、*、/等都是運(yùn)算符,運(yùn)算符的作用是與一定的運(yùn)算數(shù)據(jù)組成表達(dá)式來完成相應(yīng)的運(yùn)算。對(duì)不同的數(shù)據(jù)類型,有著不同的運(yùn)算符。

              5:分隔符。分隔符用來使編譯器確認(rèn)代碼在何處分隔。‘’‘’‘;’‘:’都是Java語言的分隔符。

              學(xué)習(xí) Java 語言很簡單,畢竟 Java 語言也只包含五十多個(gè)關(guān)鍵詞(keyword)與幾十個(gè)算符(operator),再加上 Java 語法(syntax)也很簡單,所以一般人可以很快就學(xué)會(huì) Java 語言。

             危險(xiǎn)的是,很多人認(rèn)為已經(jīng)完全掌控 Java 語言,但其實(shí)對(duì)于內(nèi)部的運(yùn)作機(jī)制仍不能掌握,這些盲點(diǎn)有時(shí)候會(huì)讓你無法完全掌控 Java 語言。

             克服這些盲點(diǎn)的方式是看「The Java Language Specification, 2nd Ed.」(沒有中文版)來徹底弄懂 Java 程序語言,并看「Inside the Java Virtual Machine, 2nd Ed.」來徹底掌握 Java 虛擬機(jī)器的運(yùn)作方式。

              學(xué)會(huì)了語言,并不代表就可以設(shè)計(jì)出好的對(duì)象導(dǎo)向系統(tǒng)架構(gòu)。想要成為對(duì)象導(dǎo)向的專家,往往需要:

          (1) 多看相關(guān)的書,特別是 Design Pattern 和 Refactoring 的書。

          (2) 多觀摩別人的程序(例如 Java API 的 design 與 implementation)

          (3) 多寫程序。

              學(xué)會(huì) Java 語言之后,還需要學(xué)會(huì)一些 API 才能寫出有用的程序。

              Java 的 API 非常多,必須規(guī)劃好一個(gè)學(xué)習(xí)路徑,才不會(huì)在浩瀚的 API 大海中迷失。必備的 API 包括了:IO、New IO、Collection Framework、Network、RMI、JAXP…… 等。

              至于其它的 API,就看你的需求而定,大致上分成:

              * GUI 類:JavaBean -> Swing -> JavaHelp -> Java2D -> Image IO -> JAI -> Java 3D ……

              * Enterprise 類:JDBC -> JDO -> Servlet -> JSP -> EJB -> JMS -> JTA/JTS……

              * J2ME 類(這一類不是我的專長,無法提供學(xué)習(xí)順序建議)

              Java語言通常都是根據(jù)Java虛擬機(jī)規(guī)范(The Java Virtual Machine Specification)中的定義,編譯為字節(jié)碼指令集和二進(jìn)制格式。因此我們接下來就討論Java虛擬機(jī)(JVM)

              JVM

              我們已經(jīng)談過Java語言的語法類似于C和C++,但是摒棄了C和C++中復(fù)雜、疑惑和不安全的特性。Java語言最早是用來構(gòu)建消費(fèi)類網(wǎng)絡(luò)設(shè)備的軟件的,因此它要支持多主機(jī)的架構(gòu),并要求能夠提供安全的軟件組件。為了滿足這些需求,編譯好的代碼就必須能夠通過網(wǎng)絡(luò)來傳播,能夠在任何客戶端上運(yùn)行,同時(shí)還要保證客戶端是足夠安全的。

              Java虛擬機(jī)是Java和Java 2 平臺(tái)的基石。它能夠保證Java語言和硬件、操作系統(tǒng)無關(guān),保證編譯后的代碼最小,并保護(hù)用戶不受惡意程序的攻擊。Java虛擬機(jī)到底是什么呢。其實(shí)它就是一臺(tái)不實(shí)際存在的計(jì)算機(jī)。和真實(shí)的計(jì)算機(jī)類似,它也有自己的指令集,并可以在運(yùn)行環(huán)境中分配內(nèi)存區(qū)域。使用虛擬機(jī)機(jī)制來實(shí)現(xiàn)編程語言并不是Java的創(chuàng)舉,這已經(jīng)是非常普遍的做法了,最著名的許你就莫過于UCSD Pascal的P-Code機(jī)。

              只要瀏覽器檢測(cè)到目前所處理的Web文件內(nèi)容含有一個(gè)Java Applet,瀏覽器將會(huì)為這個(gè)Java小程序另外開一個(gè)JVM,執(zhí)行這個(gè)Java應(yīng)用小程序。在JVM中執(zhí)行的Java小程序可以得到充分安全的保護(hù)。如同我們上面所說,JVM是一個(gè)自給自足的作業(yè)環(huán)境,就像是一臺(tái)獨(dú)立的計(jì)算機(jī)一樣。例如,在JVM運(yùn)作的Applet,無法存取主機(jī)操作系統(tǒng)。優(yōu)點(diǎn)是:

              1. 系統(tǒng)中立。Java應(yīng)用程序可以在任何JVM中運(yùn)作,不論該系統(tǒng)使用何種硬件、軟件。

              2. 安全。正因JVM跟操作系統(tǒng)沒有任何接觸,Java程序很難損害到其它檔案或應(yīng)用程序。

              缺點(diǎn)是,由于在JVM運(yùn)作的程序獨(dú)立在操作系統(tǒng)之外,也就無法享受操作系統(tǒng)各項(xiàng)特殊功能。

              Java技術(shù)之所以在今天得到了如此廣闊的應(yīng)用,其中它的安全性是不能不提的。不同于其它技術(shù)(例如Microsoft的ActiveX)中安全性作為附加設(shè)計(jì)和補(bǔ)丁,Java從設(shè)計(jì)之初便考慮到了安全性。因此Java的安全性是在語言層次實(shí)現(xiàn)的。Java的安全性由下列三個(gè)方面保證:

              1、 語言特性(包括數(shù)組的邊界檢查、類型轉(zhuǎn)換、取消指針型變量)。

              2、 資源訪問控制(包括本地文件系統(tǒng)訪問、Socket連接訪問)。

              3、 代碼數(shù)字簽名(通過數(shù)字簽名來確認(rèn)代碼源以及代碼是否完整)。

              Java的源代碼是先編譯成為一種字節(jié)碼的中間代碼,存放這種代碼的文件就是class的文件。真正執(zhí)行的時(shí)候是將class文件裝載到JVM(虛擬機(jī))中,然后由JVM解釋執(zhí)行的。所以數(shù)組的上下界檢查及合法的類型轉(zhuǎn)換是通過JVM得到保證的。Java通過一個(gè)類裝載器類(ClassLoader)將虛擬機(jī)代碼文件(即class文件)裝載到JVM中,當(dāng)完成裝載后,一個(gè)被稱做安全管理器(SecurityManager)的類開始運(yùn)行,例如當(dāng)一個(gè)Applet的class文件被缺省的類裝載器裝載到JVM中后,JVM會(huì)立即為它裝載一個(gè)SecurityManager的子類AppletSecurity,由這個(gè)管理器來驗(yàn)證操作。代碼的所有動(dòng)作(例如文件讀寫)都要先經(jīng)過驗(yàn)證,只有被該安全管理器接受的動(dòng)作才能完成,否則就會(huì)拋出SecurityException異常。

              對(duì)于JDK1.0,權(quán)限被籠統(tǒng)的劃分為兩大塊。一是擁有所有的權(quán)限,一個(gè)是僅擁有"沙箱"(sandBox)權(quán)限,這也是普通的Applet所擁有的權(quán)限。這時(shí)本地文件讀寫或是與源主機(jī)(Orignal Server)以外的主機(jī)連接都是被禁止的。這種劃分的最大問題就是缺乏靈活性。例如我們希望一個(gè)Applet在用戶信任的情況下能夠?qū)Ρ镜匚募到y(tǒng)的某個(gè)目錄進(jìn)行讀寫,但并不要通過Socket與其它主機(jī)連接。這是JDK1.0的權(quán)限劃分就不能達(dá)到要求。JDK1.1后改進(jìn)了權(quán)限的劃分,引入了權(quán)限集(PermissionSet)的概念。

              由于我們的文章并不是討論JVM,因此,我們只是對(duì)JVM做一個(gè)簡單的介紹。如果需要詳細(xì)了解的,可以參考「The JavaTM TMVirtual Machine Specification」。

              客觀的看待Java

              相對(duì)于其他編程語音,Java有一個(gè)無庸置疑的優(yōu)點(diǎn):用戶以及編譯器第一次不必了解生成可執(zhí)行代碼的特定CPU細(xì)節(jié)。Java引入了一個(gè)編譯代碼中間層,叫做字節(jié)代碼,并使用一個(gè)虛擬抽象的機(jī)器,而不是一個(gè)真實(shí)的機(jī)器。當(dāng)Java編譯器結(jié)束了一個(gè)源文件的編譯后,你所得到的不是可以立即在一個(gè)給定平臺(tái)上運(yùn)行的代碼,而是可以在任何真實(shí)的平臺(tái)上運(yùn)行的字節(jié)代碼,唯一的條件就是這個(gè)平臺(tái)要理解和支持Java.這些發(fā)展包含著一個(gè)文化的變革。作為一個(gè)開發(fā)人員,你只需要確定Java虛擬機(jī)(JVM)提供的抽象層,不同的OS銷售商負(fù)責(zé)執(zhí)行代碼層,從而將中立于平臺(tái)的字節(jié)代碼映射到主機(jī)平臺(tái)的機(jī)構(gòu)中。在這種情況下,Java似乎是統(tǒng)一分布式計(jì)算機(jī)世界的領(lǐng)袖候選人了。“編寫一次,永遠(yuǎn)運(yùn)行”(并且無論在哪里)就成為Java誘人但卻真實(shí)的口號(hào)。

              但我們平心而論,Java的跨平臺(tái)并不是一個(gè)非常誘人的特性?跨平臺(tái)理論的發(fā)展很好地證明了這一點(diǎn)。我們看到,將Java代碼從一個(gè)平臺(tái)移植到另一個(gè)平臺(tái)?Java這個(gè)語言最重要和最受吹捧的特點(diǎn)?并不象宣傳的那樣容易。任何Java平臺(tái)都有其自己的虛擬機(jī),它可以理解通用的字節(jié)代碼,并且及時(shí)地將其編譯為本地代碼。矛盾由此產(chǎn)生,不同虛擬機(jī)的執(zhí)行也很不相同,這一點(diǎn)足以使代碼的移植比預(yù)期耗費(fèi)多得多的時(shí)間,而且基本上不是自動(dòng)的。在企業(yè)用戶的角度上來說,也很少會(huì)有企業(yè)會(huì)頻繁的更換平臺(tái),因此這個(gè)特性是否能夠帶來高價(jià)值是很難評(píng)價(jià)的。

              那么,Java模型的好處在哪里呢?首先,Java是一種先進(jìn)的、面向?qū)ο蟮恼Z言,包含了預(yù)防常見錯(cuò)誤的內(nèi)置功能,并在僅僅一兩個(gè)對(duì)象中攜帶了許多經(jīng)常需要用到的功能。與C++相比,Java更易于讀寫,不容易出錯(cuò),而且更加美觀,但是它速度較慢也不太靈活。想實(shí)現(xiàn)在任何軟件和硬件平臺(tái)上都可虛擬移植,Java盡可能少地使用了公分母模型,也就是說放棄了將每個(gè)平臺(tái)開發(fā)到極限的能力。第二,虛擬機(jī)的概念本身就是可移植和可共用的,因此對(duì)于分布式環(huán)境來說是理想的。Java對(duì)于為非Windows平臺(tái)開發(fā)代碼是最好的語言。

              那么對(duì)于Windows平臺(tái)來說,Java又怎么樣呢?讓Java適應(yīng)Windows是不可能的,這是由于Sun的許可約束問題。但是Java實(shí)在是太吸引人了,Microsoft比誰都能更清楚這一點(diǎn)。Microsoft在以前推出的Visual J++證明了這一點(diǎn),但是可惜的是,Microsoft又犯了霸權(quán)的老毛病,Visual J++并不好用。因此,Microsoft又一次采取了“拿來主義”的手法,很好地利用了Java 的眾多特性,隆重推出了Windows平臺(tái)的新銳力量,它就是相當(dāng)簡單但十分強(qiáng)大的面向?qū)ο蟮腃#編程語言。C#超過了C++,它天生就包含了。NET框架類庫中的所有類,并使語法簡單化。說到這里已經(jīng)有一些離題了,不過Java也不是說在Windows平臺(tái)上就不能夠使用,JDK和大部分的IDE都支持Windows平臺(tái)。

              Java技術(shù)的架構(gòu)——J2ME、J2SE和J2EE

              通常我們以 JDK(Sun 所開發(fā)的一套 Java 開發(fā)工具)的版本來定義 Java 的版本。JDK 1.0 版于 1996 年初公開,JDK 1.1 版于 1997 年初公開,JDK 1.2 版于 1998 年底公開。基于市場(chǎng)行銷的考量,Sun 在 JDK 1.2 版公開后旋即將 Java 改名為「Java 2」,將 JDK 改名為「Java 2 Software Development Kit(以下簡稱 J2SDK)」。J2SDK(原稱 JDK)1.3 于 2000 年 4 月公開,此版本仍稱做「Java 2」。目前 J2SDK 1.4 也已經(jīng)公開了,大家可以到Sun的官方Java站點(diǎn)上查閱到大量的JDK1.4的信息。

              Java 技術(shù)根據(jù)硬件平臺(tái)與適用環(huán)境的差異,分成幾個(gè)分支。JDK 1.1 的時(shí)代,適用于一般消費(fèi)性電子產(chǎn)品等,嵌入式系統(tǒng)的 Java 平臺(tái)是 PersonalJava 與 EmbeddedJava,此二者并無明確的界線,大致上來說,運(yùn)算資源、內(nèi)存、以及顯示裝置比較豐富者,使用 PersonalJava,例如 Set-Top Box、視訊電話 …… 等;反之,資源較有限者使用 EmbeddedJava,例如呼叫器、行動(dòng)電話 …… 等。除了 PC 使用的 Java 平臺(tái)、IA 使用的 PersonalJava 與 EmbeddedJava 平臺(tái)之外,JavaCard 也是一個(gè) Java 平臺(tái),使用于 Smart Card(IC Card)上。

              Java 2 出現(xiàn)后,推翻了先前的 PersonalJava 與 EmeddedJava 的分法,改分成 Java 2 Platform Enterprise Edition(簡稱 J2EE)、Java 2 Platform Standard Edition(簡稱 J2SE)、Java 2 Platform Micro Edition(簡稱 J2ME)。J2EE 適用于服務(wù)器,目前已經(jīng)成為企業(yè)運(yùn)算、電子商務(wù)等領(lǐng)域中相當(dāng)熱門的技術(shù);J2SE 適用于一般的計(jì)算機(jī);J2ME 適用于消費(fèi)性電子產(chǎn)品。除了這三者之外,JavaCard 依然是獨(dú)立的一套標(biāo)準(zhǔn)。

              目前,Java技術(shù)的架構(gòu)包括三個(gè)方面:

              J2EE(Java 2 Platform Enterprise Edition )?企業(yè)版 (J2EE) 是為面向以企業(yè)為環(huán)境而開發(fā)應(yīng)用程序的解決方案。

              J2SE(Java 2 Platform Stand Edition)?標(biāo)準(zhǔn)版 (J2SE) 為桌面開發(fā)和低端商務(wù)應(yīng)用提供了可行的解決方案。

              J2ME(Java 2 Platform Micro Edition )?小型版(J2ME)是致力于消費(fèi)產(chǎn)品和嵌入式設(shè)備的最佳解決方案

              J2EE

              J2EE已經(jīng)成為開發(fā)商創(chuàng)建電子商務(wù)應(yīng)用的事實(shí)標(biāo)準(zhǔn)。正是認(rèn)識(shí)到J2EE平臺(tái)作為一種可擴(kuò)展的、全功能的平臺(tái),可以將關(guān)鍵的企業(yè)應(yīng)用擴(kuò)展到任何Web瀏覽器上并可適合多種不同的Internet數(shù)據(jù)流、可連接到幾乎任何一種傳統(tǒng)數(shù)據(jù)庫和解決方案、使企業(yè)經(jīng)理根據(jù)多家企業(yè)所提供的產(chǎn)品和技術(shù)開發(fā)和部署最佳的解決方案進(jìn)而降低開發(fā)網(wǎng)絡(luò)化應(yīng)用的費(fèi)用和復(fù)雜性這一巨大優(yōu)勢(shì),很多廠家都表示將對(duì)J2EE給予支持,并將J2EE技術(shù)作為大型BtoB市場(chǎng)和海量交易處理的安全穩(wěn)定的端到端平臺(tái)。J2EE技術(shù)的基礎(chǔ)就是J2SE標(biāo)準(zhǔn)版,它鞏固了標(biāo)準(zhǔn)版中的許多優(yōu)點(diǎn)。其最終目的就是成為一個(gè)能夠使企業(yè)開發(fā)者大幅縮短投放市場(chǎng)時(shí)間的體系結(jié)構(gòu)。它為靈活配置各種多層企業(yè)應(yīng)用軟件,特別是B2B、B2C等電子商務(wù)應(yīng)用,提供了強(qiáng)大的服務(wù)功能。最近又新加了Connector API服務(wù),使企業(yè)應(yīng)用的開發(fā)和部署有了一系列成熟的技術(shù)。

              J2SE

              J2SE是Java 2平臺(tái)的標(biāo)準(zhǔn)版, 它適用于桌面系統(tǒng),提供CORBA標(biāo)準(zhǔn)的ORB技術(shù),結(jié)合Java的RMI支持分布式互操作環(huán)境。它運(yùn)行在Java虛擬機(jī)上。在引入了Java IDL后, J2SE支持IIOP通信。它是高可移植性、異構(gòu)性的實(shí)現(xiàn)環(huán)境和健壯平臺(tái),也是實(shí)現(xiàn)可伸縮性、可移植性、分布式異構(gòu)互操作應(yīng)用軟件開發(fā)的標(biāo)準(zhǔn)平臺(tái)。

              J2ME

              J2ME提供了HTTP高級(jí)Internet協(xié)議,使移動(dòng)電話能以Client/Server方式直接訪問Internet的全部信息,不同的Client訪問不同的文件,此外還能訪問本地存儲(chǔ)區(qū),提供最高效率的無線交流。J2ME是Java 2平臺(tái)的微型版,它分成CDC(connected device configuration)和CLDC(connected limited device configuration)兩部分。CDC運(yùn)行在連接虛擬機(jī)上,為手提式計(jì)算機(jī)一類較復(fù)雜的移動(dòng)設(shè)備提供應(yīng)用平臺(tái);CLDC運(yùn)行在核心虛擬機(jī)(KVM)上,它實(shí)現(xiàn)MIDP(Mobile Information Device Profile)移動(dòng)信息設(shè)備應(yīng)用平臺(tái),即針對(duì)手機(jī)之類的設(shè)備建立移動(dòng)計(jì)算平臺(tái)。

              在小型的J2ME(Java 2 Micro Edition)方面,主要是應(yīng)用在內(nèi)存容量小、體積也較小的電子裝置上。小至智能卡、行動(dòng)電話,個(gè)人數(shù)字助理都是運(yùn)用J2ME的最佳平臺(tái)。Java在Palm的應(yīng)用上,PalmOS 4.0內(nèi)含KJava,Sun也推出針對(duì)PalmOS使用的J2ME版本。所以,以既有的Java程序設(shè)計(jì)知識(shí),就可以在Palm PDA上開發(fā)出Palm的各式各樣應(yīng)用系統(tǒng)。Java和Palm這兩個(gè)標(biāo)準(zhǔn)平臺(tái)的結(jié)合,將是下一波PDA應(yīng)用的趨勢(shì)。Java在手機(jī)的應(yīng)用上,Nokia、Motorola、Ericsson 都將推出利用J2ME技術(shù)的新手機(jī),所以Java程序設(shè)計(jì)師有更多的平臺(tái)可供施展。此種結(jié)合J2ME及無線通訊技術(shù)的無線開放應(yīng)用平臺(tái),將提供行動(dòng)商務(wù)極佳的解決方案。

              在中型的J2SE(Java 2 Standard Edition)方面,Sun推出一個(gè)新的解決方案,稱為Java Web Start.原先的Java Applet是在WebBrowser 中間開出一塊方形區(qū)域來執(zhí)行Java程序,但是這樣在執(zhí)行效能和兼容性上都受限于原有的 Web Browser.現(xiàn)在新推出的Java Web Start則是在操作系統(tǒng)上直接執(zhí)行的Java Application,但是可以在網(wǎng)頁上激活。如此一來既可和網(wǎng)頁結(jié)合,在執(zhí)行上也更快、更有效率。并且,Sun和IBM都將推出支持64位運(yùn)算的Java版本,這對(duì)一般計(jì)算機(jī)上執(zhí)行的客戶端Java應(yīng)用系統(tǒng)的開發(fā)將會(huì)是一大利器。

              另外在大型的J2EE(Java 2 Enterprise Edition)應(yīng)用上,可以說"J2EE"已經(jīng)成為服務(wù)器運(yùn)算環(huán)境的標(biāo)準(zhǔn)。Java Servlets、JSP(Java ServerPages)、EJB(Enterprise JavaBeans)、JavaMail、JDBC、JMS等,都是各家廠商產(chǎn)品開發(fā)的重點(diǎn)方向。J2EE兼容的是一般Intel個(gè)人計(jì)算機(jī)(Linux、Windows……)、麥金塔以及各家高效能高穩(wěn)定度的UNIX伺服主機(jī),未來必定成為服務(wù)器運(yùn)算市場(chǎng)上的主要選擇之一。

              除了以上這三大Java組合之外,Java和XML的整合也是未來的重點(diǎn)。Sun公司已經(jīng)推出Java處理XML的標(biāo)準(zhǔn)延伸API - Java API for XML Parsing (JAXP),可以讓各家所制作的XML解析器有接口上的標(biāo)準(zhǔn)。所以在Java程序中,只要了解一套API(JAXP)就可以完全處理XML文件,讓XML的應(yīng)用更加方便。Java這個(gè)跨平臺(tái)的開發(fā)環(huán)境,加上XML這個(gè)跨平臺(tái)的資料格式,此種跨平臺(tái)優(yōu)勢(shì)組合勢(shì)將成為未來訊息傳遞及資料交換的主要應(yīng)用技術(shù),如虎添翼地結(jié)合成一個(gè)最佳的跨平臺(tái)解決方案。

              藉由J2SE (Java 2 Standard Edition)可以開發(fā)在PC上的應(yīng)用軟件,藉由J2ME (Java 2 Micro Edition) 可以跨足更廣大的家電、智能卡、電子裝置等市場(chǎng),再藉由J2EE (Java 2 Enterprise Edition ) 可以整合伺服主機(jī)運(yùn)算環(huán)境。Java技術(shù)的應(yīng)用范圍幾乎已經(jīng)無所不在,Java技術(shù)更可以在網(wǎng)際網(wǎng)絡(luò)及電子商務(wù)各領(lǐng)域中,提供全方位的解決方案。

              隨著應(yīng)用領(lǐng)域的不同,Java 有許多 API(Application Programming Interface),這些 API 分成三大類:

              ? Java Core API:由 Sun 制定的基本 API,任何 Java 平臺(tái)都必須提供。

              ? Java Standard Extension API (javax):由 Sun 制定的擴(kuò)充 API,Java 平臺(tái)可以選擇性地提供或加裝。

              ? 廠商或組織所提供的 API:由各家公司或組織所提供。

              其中 Core API 和 Standard Extension API 已經(jīng)逐漸涵蓋了大部份的信息應(yīng)用領(lǐng)域,例如多媒體、數(shù)據(jù)庫、Web、企業(yè)運(yùn)算、語音、實(shí)時(shí)系統(tǒng)、網(wǎng)絡(luò)、電話、影像處理、加解密、GUI、分布式運(yùn)算 ……。如果你有某項(xiàng)需求尚未有標(biāo)準(zhǔn)的 Java API 可遵循,你可以向 Sun 提出制定新 API 的請(qǐng)求。經(jīng)過審核之后,你的要求可能會(huì)通過、駁回 …… 等。如果通過,就會(huì)開始進(jìn)入制定 API 的程序。Java API 的制定過程因?yàn)楣_,且經(jīng)過許多業(yè)界技術(shù)領(lǐng)先公司的共同參與,所以相當(dāng)完善而優(yōu)異。

              EJB的生態(tài)環(huán)境

              在sun公司提供的EJB規(guī)范中,我們一個(gè)完整的基于EJB的分布式計(jì)算結(jié)構(gòu)由六個(gè)角色組成,這六個(gè)角色可以由不同的開發(fā)商提供,每個(gè)角色所作的工作必須遵循Sun公司提供的EJB規(guī)范,以保證彼此之間的兼容性。

              EJB組件開發(fā)者: 開發(fā)并銷售 EJB.應(yīng)用組合者: 將不同的 EJB 搭建成應(yīng)用。

              部署者: 使用相應(yīng)工具在運(yùn)行環(huán)境下配置 EJB. EJB 服務(wù)器提供者: 開發(fā)并銷售 EJB 服務(wù)器EJB 容器供應(yīng)商: 開發(fā)并銷售 EJB 容器系統(tǒng)管理員: 監(jiān)視運(yùn)行時(shí)情況

              1、EJB組件開發(fā)者(Enterprise Bean Provider)

              EJB組件開發(fā)者負(fù)責(zé)開發(fā)執(zhí)行商業(yè)邏輯規(guī)則的EJB組件,開發(fā)出的EJB組件打包成ejb-jar文件。EJB組件開發(fā)者負(fù)責(zé)定義EJB的remote和home接口,編寫執(zhí)行商業(yè)邏輯的EJB class,提供部署EJB的部署文件(deployment descriptor)。部署文件包含EJB的名字,EJB用到的資源配置,如JDBC等。EJB組件開發(fā)者是典型的商業(yè)應(yīng)用開發(fā)領(lǐng)域?qū)<摇?/p>

              EJB組件開發(fā)者不需要精通系統(tǒng)級(jí)的編程,因此,不需要知道一些系統(tǒng)級(jí)的處理細(xì)節(jié),如事務(wù)、同步、安全、分布式計(jì)算等。

              2、應(yīng)用組合者(Application Assembler)

              應(yīng)用組合者負(fù)責(zé)利用各種EJB組合一個(gè)完整的應(yīng)用系統(tǒng)。應(yīng)用組合者有時(shí)需要提供一些相關(guān)的程序,如在一個(gè)電子商務(wù)系統(tǒng)里,應(yīng)用組合者需要提供JSP(Java Server Page)程序。

              應(yīng)用組合者必須掌握所用的EJB的home和remote接口,但不需要知道這些接口的實(shí)現(xiàn)。

              3、部署者(Deployer)

              部署者負(fù)責(zé)將ejb-jar文件部署到用戶的系統(tǒng)環(huán)境中。系統(tǒng)環(huán)境包含某種EJB Server和EJB Container.部署者必須保證所有由EJB組件開發(fā)者在部署文件中聲明的資源可用,例如,部署者必須配置好EJB所需的數(shù)據(jù)庫資源。

              部署過程分兩步:部署者首先利用EJB Container提供的工具生成一些類和接口,使EJB Container能夠利用這些類和接口在運(yùn)行狀態(tài)管理EJB. 部署者安裝EJB組件和其他在上一步生成的類到EJB Container中。 部署者是某個(gè)EJB運(yùn)行環(huán)境的專家。

              某些情況下,部署者在部署時(shí)還需要了解EJB包含的業(yè)務(wù)方法,以便在部署完成后,寫一些簡單的程序測(cè)試。

              4、EJB 服務(wù)器提供者(EJB Server Provider)

              EJB 服務(wù)器提供者是系統(tǒng)領(lǐng)域的專家,精通分布式交易管理,分布式對(duì)象管理及其它系統(tǒng)級(jí)的服務(wù)。EJB 服務(wù)器提供者一般由操作系統(tǒng)開發(fā)商、中間件開發(fā)商或數(shù)據(jù)庫開發(fā)商提供。

              在目前的EJB規(guī)范中,假定EJB 服務(wù)器提供者和EJB 容器提供者來自同一個(gè)開發(fā)商,所以,沒有定義EJB 服務(wù)器提供者和EJB容器提供者之間的接口標(biāo)準(zhǔn)。

              5、EJB 容器提供者(EJB Container Provider)

              EJB 容器提供者提供以下功能:

              提供EJB部署工具為部署好的EJB組件提供運(yùn)行環(huán)境 .EJB容器負(fù)責(zé)為EJB提供交易管理,安全管理等服務(wù)。

              EJB 容器提供者必須是系統(tǒng)級(jí)的編程專家,還要具備一些應(yīng)用領(lǐng)域的經(jīng)驗(yàn)。EJB 容器提供者的工作主要集中在開發(fā)一個(gè)可伸縮的,具有交易管理功能的集成在EJB 服務(wù)器中的容器。EJB 容器提供者為EJB組件開發(fā)者提供了一組標(biāo)準(zhǔn)的、易用的API訪問EJB 容器,使EJB組件開發(fā)者不需要了解EJB服務(wù)器中的各種技術(shù)細(xì)節(jié)。

              EJB容器提供者負(fù)責(zé)提供系統(tǒng)監(jiān)測(cè)工具用來實(shí)時(shí)監(jiān)測(cè)EJB容器和運(yùn)行在容器中的EJB組件狀態(tài)。

              6、系統(tǒng)管理員(System Administrator)

              系統(tǒng)管理員負(fù)責(zé)為EJB服務(wù)器和容器提供一個(gè)企業(yè)級(jí)的計(jì)算和網(wǎng)絡(luò)環(huán)境。

              系統(tǒng)管理員負(fù)責(zé)利用EJB 服務(wù)器和容器提供的監(jiān)測(cè)管理工具監(jiān)測(cè)EJB組件的運(yùn)行情況。

              將責(zé)任分離的另一個(gè)好處是在代碼級(jí)上,可以將基于EJBs的系統(tǒng)邏輯的分派給更適合的專家。SUN的EJB規(guī)范建議使用幾個(gè)獨(dú)立的角色,對(duì)于確定運(yùn)作環(huán)境的責(zé)任鏈?zhǔn)欠浅V匾摹Ee例說,EJB提供者是由商業(yè)專家和分析人員扮演的角色,他們確定一個(gè)組織內(nèi)的最佳信息流程。但是仍舊有Second Domain Expert,如應(yīng)用程序匯編人員,他們集成不同的EJB組件并確保它可以確保滿足應(yīng)用程序的需求。

              還有兩種角色歸入到系統(tǒng)級(jí)的部分,第一個(gè)是配置人員,他們負(fù)責(zé)實(shí)際的安裝和配置基于EJB的系統(tǒng)。這需要有設(shè)置目錄服務(wù)和集成現(xiàn)有應(yīng)用程序的經(jīng)驗(yàn)。第二個(gè)是系統(tǒng)管理員,他們要提供全天的監(jiān)視和支持,確保應(yīng)用程序正常運(yùn)作。盡管系統(tǒng)管理員這個(gè)角色不需要是Java編程專家,但是他需要能夠應(yīng)付以下問題:

              設(shè)置Java Virtual Machine (JVM)并關(guān)聯(lián)系統(tǒng)環(huán)境參數(shù)(如:CLASSPATH)

              使用Java Archive (jar)命令保存類文件懂得WEB服務(wù)器和Servlet的工作原理。

              要能通過監(jiān)視運(yùn)行中程序的狀態(tài)確定優(yōu)化方法。

              很明顯,有些角色是可以交叉的,比如系統(tǒng)管理員和配置人員。盡管配置人員可能是將類文件復(fù)制到服務(wù)器而系統(tǒng)管理員需要確定配置人員是否復(fù)制到了正確的位置.

          EJB技術(shù)的基礎(chǔ)是另外兩種技術(shù):RMI-IIOP和JNDI.

              要想了解EJB,一定要先了解RMI-IIOP和JNDI.因此,我們?cè)诮榻BEJB細(xì)節(jié)之前,先了解這兩項(xiàng)技術(shù)。我們的介紹比較基本,因此大多數(shù)組織只要了解這些就已經(jīng)夠了。

              Java RMI-IIOP

              Java RMI-IIOP(Java Remote Method Invocation over the Internet Inter-ORB Protocol)是J2EE的網(wǎng)絡(luò)機(jī)制。Java RMI-IIOP允許你編寫分布式對(duì)象,使得對(duì)象的通信范圍能夠在內(nèi)存中,跨Java虛擬機(jī),跨物理設(shè)備。

              Remote Method Invocation

              RPC(remote procedure call)是一臺(tái)機(jī)器的進(jìn)程調(diào)用另一臺(tái)機(jī)器的進(jìn)程的過程。而remote method invocation則比RPC的概念更進(jìn)一步,允許分布式對(duì)象間的通信。RMI-IIOP允許調(diào)用遠(yuǎn)程對(duì)象的方法,而不僅僅是過程。這有利于面向?qū)ο缶幊獭ava RMI (Remote Method Invocation 遠(yuǎn)程方法調(diào)用)是用Java在JDK1.1中實(shí)現(xiàn)的,它大大增強(qiáng)了Java開發(fā)分布式應(yīng)用的能力。Java作為一種風(fēng)靡一時(shí)的網(wǎng)絡(luò)開發(fā)語言,其巨大的威力就體現(xiàn)在它強(qiáng)大的開發(fā)分布式網(wǎng)絡(luò)應(yīng)用的能力上,而RMI就是開發(fā)百分之百純Java的網(wǎng)絡(luò)分布式應(yīng)用系統(tǒng)的核心解決方案之一。其實(shí)它可以被看作是RPC的Java版本。但是傳統(tǒng)RPC并不能很好地應(yīng)用于分布式對(duì)象系統(tǒng)。而Java RMI 則支持存儲(chǔ)于不同地址空間的程序級(jí)對(duì)象之間彼此進(jìn)行通信,實(shí)現(xiàn)遠(yuǎn)程對(duì)象之間的無縫遠(yuǎn)程調(diào)用。

              remote method invocation決不簡單,需要考慮幾個(gè)問題:

              marshalling和unmarshalling.在不同機(jī)器間通過網(wǎng)絡(luò)傳遞變量(包括Java基本類型和對(duì)象),如果目標(biāo)機(jī)器表示數(shù)據(jù)的方式和原機(jī)器不同該怎么辦?例如二進(jìn)制庫不同。因此marshalling和unmarshalling就是傳遞變量的過程。

              變量傳遞方法。變量有兩種傳遞方法:pass-by-value和pass-by-reference.

             對(duì)于前者,你的目標(biāo)方法只需使用一份copy,但對(duì)于后者,遠(yuǎn)程方法對(duì)變量的任何修改都會(huì)影響到源數(shù)據(jù)。

              網(wǎng)絡(luò)和機(jī)器的不穩(wěn)定。需要有一種機(jī)制保證一個(gè)JVM崩潰之后,不會(huì)影響系統(tǒng)的正常運(yùn)作。

              在 Java 分布式對(duì)象模型中,remote object 是這樣一種對(duì)象:它的方法可以從其它 Java 虛擬機(jī)(可能在不同的主機(jī)上)中調(diào)用。該類型的對(duì)象由一種或多種 remote interfaces(它是聲明遠(yuǎn)程對(duì)象方法的 Java 接口)描述。遠(yuǎn)程方法調(diào)用 (RMI) 就是調(diào)用遠(yuǎn)程對(duì)象上遠(yuǎn)程接口的方法的動(dòng)作。更為重要的是,遠(yuǎn)程對(duì)象的方法調(diào)用與本地對(duì)象的方法調(diào)用語法相同。

              Remote Interface

              RMI-IIOP遵循了接口和實(shí)現(xiàn)的原則。你寫的所有網(wǎng)絡(luò)代碼都是應(yīng)用于接口,而不是實(shí)現(xiàn)。實(shí)際上,你必須使用RMI-IIOP中的范例,沒有其它的選擇。直接在你的對(duì)象實(shí)現(xiàn)上執(zhí)行遠(yuǎn)程調(diào)用是不可能的,你只能在對(duì)象類的接口上單獨(dú)進(jìn)行這一操作。

              所以我們?cè)谑褂肦MI-IIOP時(shí),你必須建立一個(gè)客戶接口,叫做remote interface.這個(gè)遠(yuǎn)程接口應(yīng)該擴(kuò)展java.rmi.Remote接口。

              Remote Object Implementation

              遠(yuǎn)程對(duì)象和客戶機(jī)的物理位置并不是很重要。可以運(yùn)行在同一地址空間或是跨Internet運(yùn)行。

              為了使對(duì)象成為一個(gè)遠(yuǎn)程對(duì)象,你需要執(zhí)行一下步驟:

              繼承javax.rmi.PortableRemoteObject.PortableRemoteObject是進(jìn)行遠(yuǎn)程調(diào)用的基類,當(dāng)你的遠(yuǎn)程對(duì)象調(diào)用構(gòu)造器時(shí),PortableRemoteObject對(duì)象的構(gòu)造器也會(huì)自動(dòng)被調(diào)用。

              不繼承javax.rmi.PortableRemoteObject.如果你的遠(yuǎn)程對(duì)象需要繼承其它的類,而Java不允許多重繼承,因此你不能繼承PortableRemoteObject.這時(shí),你需要手動(dòng)調(diào)用javax.rmi.PortableRemoteObject.exportObject()。

              Stub和Skeletons

              我們來看看在RMI-IIOP背后隱藏的網(wǎng)絡(luò)架構(gòu)。RMI-IIOP的一個(gè)好處就是你可以不用管你要調(diào)用的對(duì)象是本地的還是遠(yuǎn)程的。這就叫做local/remote transparency.

              RMI應(yīng)用程序通常包括兩個(gè)獨(dú)立的程序:服務(wù)器程序和客戶機(jī)程序。典型的服務(wù)器應(yīng)用程序?qū)?chuàng)建多個(gè)遠(yuǎn)程對(duì)象,使這些遠(yuǎn)程對(duì)象能夠被引用,然后等待客戶機(jī)調(diào)用這些遠(yuǎn)程對(duì)象的方法。而典型的客戶機(jī)程序則從服務(wù)器中得到一個(gè)或多個(gè)遠(yuǎn)程對(duì)象的引用,然后調(diào)用遠(yuǎn)程對(duì)象的方法。RMI為服務(wù)器和客戶機(jī)進(jìn)行通信和信息傳遞提供了一種機(jī)制。

              在與遠(yuǎn)程對(duì)象的通信過程中,RMI使用標(biāo)準(zhǔn)機(jī)制:stub和skeleton.遠(yuǎn)程對(duì)象的stub擔(dān)當(dāng)遠(yuǎn)程對(duì)象的客戶本地代表或代理人角色。

             調(diào)用程序?qū)⒄{(diào)用本地stub的方法,而本地stub將負(fù)責(zé)執(zhí)行對(duì)遠(yuǎn)程對(duì)象的方法調(diào)用。

             在RMI中,遠(yuǎn)程對(duì)象的stub與該遠(yuǎn)程對(duì)象所實(shí)現(xiàn)的遠(yuǎn)程接口集相同。

             調(diào)用stub的方法時(shí)將執(zhí)行下列操作:

          (1) 初始化與包含遠(yuǎn)程對(duì)象的遠(yuǎn)程虛擬機(jī)的連接;

          (2) 對(duì)遠(yuǎn)程虛擬機(jī)的參數(shù)進(jìn)行編組(寫入并傳輸);

          (3) 等待方法調(diào)用結(jié)果;

          (4) 解編(讀取)返回值或返回的異常;

          (5) 將值返回給調(diào)用程序。

             為了向調(diào)用程序展示比較簡單的調(diào)用機(jī)制,stub將參數(shù)的序列化和網(wǎng)絡(luò)級(jí)通信等細(xì)節(jié)隱藏了起來。在遠(yuǎn)程虛擬機(jī)中,每個(gè)遠(yuǎn)程對(duì)象都可以有相應(yīng)的skeleton(在JDK1.2環(huán)境中無需使用skeleton)。

             Skeleton負(fù)責(zé)將調(diào)用分配給實(shí)際的遠(yuǎn)程對(duì)象實(shí)現(xiàn)。

             它在接收方法調(diào)用時(shí)執(zhí)行下列操作:

          (1) 解編(讀取)遠(yuǎn)程方法的參數(shù);

          (2) 調(diào)用實(shí)際遠(yuǎn)程對(duì)象實(shí)現(xiàn)上的方法;

          (3) 將結(jié)果(返回值或異常)編組(寫入并傳輸)給調(diào)用程序。

              stub和skeleton由rmic編譯器生成。

              要實(shí)現(xiàn)local/remote transparency可沒有那么簡單。為了屏蔽你調(diào)用的是遠(yuǎn)端主機(jī)上的對(duì)象,RMI-IIOP需要模擬一個(gè)本地對(duì)象供你調(diào)用。這個(gè)本地對(duì)象叫做stub.它負(fù)責(zé)接受本地的方法調(diào)用請(qǐng)求,把這些請(qǐng)求委托給真正實(shí)現(xiàn)它們的對(duì)象(可以通過網(wǎng)絡(luò)定位)。這樣就使得遠(yuǎn)程調(diào)用看起來就和本地調(diào)用一樣。

              利用RMI編寫分布式對(duì)象應(yīng)用程序需要完成以下工作:

          (1) 定位遠(yuǎn)程對(duì)象。應(yīng)用程序可使用兩種機(jī)制中的一種得到對(duì)遠(yuǎn)程對(duì)象的引用。它既可用RMI的簡單命名工具rmiregistry來注冊(cè)它的遠(yuǎn)程對(duì)象,也可以將遠(yuǎn)程對(duì)象引用作為常規(guī)操作的一部分來進(jìn)行傳遞和返回。

          (2)與遠(yuǎn)程對(duì)象通信。遠(yuǎn)程對(duì)象間通信的細(xì)節(jié)由RMI處理,對(duì)于程序員來說,遠(yuǎn)程通信看起來就像標(biāo)準(zhǔn)的Java方法調(diào)用。

          (3)給作為參數(shù)或返回值傳遞的對(duì)象加載類字節(jié)碼。因?yàn)镽MI允許調(diào)用程序?qū)⒓僇ava對(duì)象傳給遠(yuǎn)程對(duì)象,所以,RMI將提供必要的機(jī)制,既可以加載對(duì)象的代碼又可以傳輸對(duì)象的數(shù)據(jù)。

              在RMI分布式應(yīng)用程序運(yùn)行時(shí),服務(wù)器調(diào)用注冊(cè)服務(wù)程序以使名字與遠(yuǎn)程對(duì)象相關(guān)聯(lián)。客戶機(jī)在服務(wù)器上的注冊(cè)服務(wù)程序中用遠(yuǎn)程對(duì)象的名字查找該遠(yuǎn)程對(duì)象,然后調(diào)用它的方法。

              定位遠(yuǎn)程對(duì)象。應(yīng)用程序可使用兩種機(jī)制中的一種得到對(duì)遠(yuǎn)程對(duì)象的引用。它既可用 RMI 的簡單命名工具 rmiregistry 來注冊(cè)它的遠(yuǎn)程對(duì)象;也可將遠(yuǎn)程對(duì)象引用作為常規(guī)操作的一部分來進(jìn)行傳遞和返回。

              與遠(yuǎn)程對(duì)象通訊。遠(yuǎn)程對(duì)象間通訊的細(xì)節(jié)由 RMI 處理;對(duì)于程序員來說,遠(yuǎn)程通訊看起來就象標(biāo)準(zhǔn)的 Java 方法調(diào)用。給作為參數(shù)或返回值傳遞的對(duì)象加載類字節(jié)碼因?yàn)?RMI允許調(diào)用程序?qū)⒓?Java 對(duì)象傳給遠(yuǎn)程對(duì)象,所以 RMI 將提供必要的機(jī)制,既可以加載對(duì)象的代碼又可以傳輸對(duì)象的數(shù)據(jù)。服務(wù)器調(diào)用注冊(cè)服務(wù)程序以使名字與遠(yuǎn)程對(duì)象相關(guān)聯(lián)。客戶機(jī)在服務(wù)器注冊(cè)服務(wù)程序中用遠(yuǎn)程對(duì)象的名字查找該遠(yuǎn)程對(duì)象,然后調(diào)用它的方法。RMI 能用 Java系統(tǒng)支持的任何 URL 協(xié)議(例如 HTTP、FTP、file 等)加載類字節(jié)碼。

              stub只是解決了一半的問題。我們還希望遠(yuǎn)程對(duì)象也不用考慮網(wǎng)絡(luò)問題。因此遠(yuǎn)程對(duì)象也需要一個(gè)本地的skeleton來接受調(diào)用。skeleton接受網(wǎng)絡(luò)調(diào)用并把調(diào)用委托給遠(yuǎn)程對(duì)象實(shí)現(xiàn)。

              你的J2EE服務(wù)器應(yīng)當(dāng)提供一種方法來產(chǎn)生必須的stub和skeleton,以減輕你的對(duì)網(wǎng)絡(luò)問題考慮的負(fù)擔(dān)。典型的是通過命令行工具來完成,例如sun的J2EE參考實(shí)現(xiàn)包就使用了一個(gè)名為rmic(RMI compiler)的工具來產(chǎn)生stub和skeleton類。你應(yīng)當(dāng)把stub部署在客戶機(jī)上,并把skeleton部署在服務(wù)器上。

              對(duì)象序列化和變量傳遞

              在RMI分布式應(yīng)用系統(tǒng)中,服務(wù)器與客戶機(jī)之間傳遞的Java對(duì)象必須是可序列化的對(duì)象。不可序列化的對(duì)象不能在對(duì)象流中進(jìn)行傳遞。對(duì)象序列化擴(kuò)展了核心Java輸入/輸出類,同時(shí)也支持對(duì)象。對(duì)象序列化支持把對(duì)象編碼以及將通過它們可訪問到的對(duì)象編碼變成字節(jié)流;同時(shí),它也支持流中對(duì)象圖形的互補(bǔ)重構(gòu)造。序列化用于輕型持久性和借助于套接字或遠(yuǎn)程方法調(diào)用(RMI)進(jìn)行的通信。序列化中現(xiàn)在包括一個(gè) API(Application Programming Interface,應(yīng)用程序接口),允許獨(dú)立于類的域指定對(duì)象的序列化數(shù)據(jù),并允許使用現(xiàn)有協(xié)議將序列化數(shù)據(jù)域?qū)懭肓髦谢驈牧髦凶x取,以確保與缺省讀寫機(jī)制的兼容性。

              為編寫應(yīng)用程序,除多數(shù)瞬態(tài)應(yīng)用程序外,都必須具備存儲(chǔ)和檢索 Java對(duì)象的能力。以序列化方式存儲(chǔ)和檢索對(duì)象的關(guān)鍵在于提供重新構(gòu)造該對(duì)象所需的足夠?qū)ο鬆顟B(tài)。

             存儲(chǔ)到流的對(duì)象可能會(huì)支持 Serializable(可序列化)或 Externalizable(可外部化)接口。

             對(duì)于Java對(duì)象,序列化形式必須能標(biāo)識(shí)和校驗(yàn)存儲(chǔ)其內(nèi)容的對(duì)象所屬的 Java類,并且將該內(nèi)容還原為新的實(shí)例。

             對(duì)于可序列化對(duì)象,流將提供足夠的信息將流的域還原為類的兼容版本。

              對(duì)于可外部化對(duì)象,類將全權(quán)負(fù)責(zé)其內(nèi)容的外部格式。

              序列化 Java 對(duì)象的目的是:

             提供一種簡單但可擴(kuò)充的機(jī)制,以序列化方式維護(hù) Java對(duì)象的類型及安全屬性;具有支持編組和解編的擴(kuò)展能力以滿足遠(yuǎn)程對(duì)象的需要;具有可擴(kuò)展性以支持 Java 對(duì)象的簡單持久性;只有在自定義時(shí),才需對(duì)每個(gè)類提供序列化自實(shí)現(xiàn);允許對(duì)象定義其外部格式。

              java.rmi.Remote 接口

              在 RMI 中,遠(yuǎn)程接口是聲明了可從遠(yuǎn)程 Java 虛擬機(jī)中調(diào)用的方法集。遠(yuǎn)程接口必須滿足下列要求:

              遠(yuǎn)程接口至少必須直接或間接擴(kuò)展 java.rmi.Remote 接口。

              遠(yuǎn)程接口中的方法聲明必須滿足下列遠(yuǎn)程方法聲明的要求:遠(yuǎn)程方法聲明在其 throws 子句中除了要包含與應(yīng)用程序有關(guān)的異常(注意與應(yīng)用程序有關(guān)的異常無需擴(kuò)展 java.rmi.RemoteException )之外,還必須包括 java.rmi.RemoteException 異常(或它的超類,例如java.io.IOException 或 java.lang.Exception )。

              遠(yuǎn)程方法聲明中,作為參數(shù)或返回值聲明的(在參數(shù)表中直接聲明或嵌入到參數(shù)的非遠(yuǎn)程對(duì)象中)遠(yuǎn)程對(duì)象必須聲明為遠(yuǎn)程接口,而非該接口的實(shí)現(xiàn)類。

              java.rmi.Remote 接口是一個(gè)不定義方法的標(biāo)記接口:

              public interface Remote

              遠(yuǎn)程接口必須至少擴(kuò)展 java.rmi.Remote 接口(或其它擴(kuò)展java.rmi.Remote 的遠(yuǎn)程接口)。然而,遠(yuǎn)程接口在下列情況中可以擴(kuò)展非遠(yuǎn)程接口:

              遠(yuǎn)程接口也可擴(kuò)展其它非遠(yuǎn)程接口,只要被擴(kuò)展接口的所有方法(如果有)滿足遠(yuǎn)程方法聲明的要求。

              例如,下面的接口 BankAccount 即為訪問銀行帳戶定義了一個(gè)遠(yuǎn)程接口。它包含往帳戶存款、使帳戶收支平衡和從帳戶取款的遠(yuǎn)程方法:

          public interface BankAccount extends java.rmi.Remote 

          public void deposit(float amount) 
          throws java.rmi.RemoteException; 
          public void withdraw(float amount) 
          throws OverdrawnException, java.rmi.RemoteException; 
          public float getBalance() 
          throws java.rmi.RemoteException; 

              下例說明了有效的遠(yuǎn)程接口 Beta.它擴(kuò)展非遠(yuǎn)程接口 Alpha(有遠(yuǎn)程方法)和接口 java.rmi.Remote:

          public interface Alpha 

          public final String okay = "constants are okay too"; 
          public Object foo(Object obj) 
          throws java.rmi.RemoteException; 
          public void bar() throws java.io.IOException; 
          public int baz() throws java.lang.Exception; 


          public interface Beta extends Alpha, java.rmi.Remote { 
          public void ping() throws java.rmi.RemoteException; 

              RemoteException 類

              java.rmi.RemoteException 類是在遠(yuǎn)程方法調(diào)用期間由 RMI 運(yùn)行時(shí)所拋出的異常的超類。為確保使用 RMI 系統(tǒng)的應(yīng)用程序的健壯性,遠(yuǎn)程接口中聲明的遠(yuǎn)程方法在其 throws 子句中必須指定 java.rmi.RemoteException(或它的超類,例如 java.io.IOException 或 java.lang.Exception)。

              當(dāng)遠(yuǎn)程方法調(diào)用由于某種原因失敗時(shí),將拋出 java.rmi.RemoteException 異常。遠(yuǎn)程方法調(diào)用失敗的原因包括:

              通訊失敗(遠(yuǎn)程服務(wù)器不可達(dá)或拒絕連接;連接被服務(wù)器關(guān)閉等。)

              參數(shù)或返回值傳輸或讀取時(shí)失敗協(xié)議錯(cuò)誤

              RemoteException 類是一個(gè)已檢驗(yàn)的異常(必須由遠(yuǎn)程方法的調(diào)用程序處理并經(jīng)編譯器檢驗(yàn)的異常),而不是 RuntimeException.

              RemoteObject 類及其子類

              RMI 服務(wù)器函數(shù)由 java.rmi.server.RemoteObject 及其子類java.rmi.server.RemoteServer、java.rmi.server.UnicastRemoteObject和 java.rmi.activation.Activatable 提供。

              java.rmi.server.RemoteObject 為對(duì)遠(yuǎn)程對(duì)象敏感的 java.lang.Object方法、hashCode、 equals 和 toString 提供實(shí)現(xiàn)。

              創(chuàng)建遠(yuǎn)程對(duì)象并將其導(dǎo)出(使它們可為遠(yuǎn)程客戶機(jī)利用)所需的方法由類UnicastRemoteObject 和 Activatable 提供。子類可以識(shí)別遠(yuǎn)程引用的語義,例如服務(wù)器是簡單的遠(yuǎn)程對(duì)象還是可激活的遠(yuǎn)程對(duì)象(調(diào)用時(shí)將執(zhí)行的遠(yuǎn)程對(duì)象)。java.rmi.server.UnicastRemoteObject 類定義了單體(單路傳送)遠(yuǎn)程對(duì)象,其引用只有在服務(wù)器進(jìn)程活著時(shí)才有效。類 java.rmi.activation.Activatable 是抽象類,它定義的 activatable遠(yuǎn)程對(duì)象在其遠(yuǎn)程方法被調(diào)用時(shí)開始執(zhí)行并在必要時(shí)自己關(guān)閉。

              實(shí)現(xiàn)遠(yuǎn)程接口

              實(shí)現(xiàn)遠(yuǎn)程接口的類的一般規(guī)則如下:

              該類通常擴(kuò)展 java.rmi.server.UnicastRemoteObject,因而將繼承類java.rmi.server.RemoteObject 和java.rmi.server.RemoteServer 提供的遠(yuǎn)程行為。

              該類能實(shí)現(xiàn)任意多的遠(yuǎn)程接口。

              該類能擴(kuò)展其它遠(yuǎn)程實(shí)現(xiàn)類。

              該類能定義遠(yuǎn)程接口中不出現(xiàn)的方法,但這些方法只能在本地使用而不能在遠(yuǎn)程使用。

              例如,下面的類 BankAcctImpl 實(shí)現(xiàn) BankAccount 遠(yuǎn)程接口并擴(kuò)展java.rmi.server.UnicastRemoteObject 類:

              package mypackage; 

          import java.rmi.RemoteException; 
          import java.rmi.server.UnicastRemoteObject; 

          public class BankAccountImpl extends UnicastRemoteObject implements 
          BankAccount 


          private float balance = 0.0; 

          public BankAccountImpl(float initialBalance) 
          throws RemoteException 

          balance = initialBalance; 


          public void deposit(float amount) throws RemoteException 

          ... 


          public void withdraw(float amount) throws OverdrawnException, 
          RemoteException 

          ... 


          public float getBalance() throws RemoteException 

          ... 


              注意:必要時(shí),實(shí)現(xiàn)遠(yuǎn)程接口的類能擴(kuò)展除java.rmi.server.UnicastRemoteObject 類以外的其它一些類。但實(shí)現(xiàn)類此時(shí)必須承擔(dān)起一定的責(zé)任,即導(dǎo)出對(duì)象(由 UnicastRemoteObject 構(gòu)造函數(shù)負(fù)責(zé))和實(shí)現(xiàn)從 java.lang.Object 類繼承的 hashCode、 equals 和toString 方法的正確遠(yuǎn)程語義(如果需要)。

              遠(yuǎn)程方法調(diào)用中的參數(shù)傳遞

              傳給遠(yuǎn)程對(duì)象的參數(shù)或源于它的返回值可以是任意可序列化的 Java 對(duì)象。這包括 Java 基本類型, 遠(yuǎn)程?Java 對(duì)象和實(shí)現(xiàn) java.io.Serializable 接口的非遠(yuǎn)程 Java 對(duì)象。有關(guān)如何使類序列化的詳細(xì)信息,參見 Java“對(duì)象序列化規(guī)范”。本地得不到的作為參數(shù)或返回值的類,可通過 RMI 系統(tǒng)進(jìn)行動(dòng)態(tài)下載。

              傳遞非遠(yuǎn)程對(duì)象

              非遠(yuǎn)程對(duì)象將作為遠(yuǎn)程方法調(diào)用的參數(shù)傳遞或作為遠(yuǎn)程方法調(diào)用的結(jié)果返回時(shí),是通過復(fù)制傳遞的;也就是使用 Java 對(duì)象序列化機(jī)制將該對(duì)象序列化。因此,在遠(yuǎn)程對(duì)象調(diào)用過程中,當(dāng)非遠(yuǎn)程對(duì)象作為參數(shù)或返回值傳遞時(shí),非遠(yuǎn)程對(duì)象的內(nèi)容在調(diào)用遠(yuǎn)程對(duì)象之前將被復(fù)制。從遠(yuǎn)程方法調(diào)用返回非遠(yuǎn)程對(duì)象時(shí),將在調(diào)用的虛擬機(jī)中創(chuàng)建新對(duì)象。

              傳遞遠(yuǎn)程對(duì)象

              當(dāng)將遠(yuǎn)程對(duì)象作為遠(yuǎn)程方法調(diào)用的參數(shù)或返回值傳遞時(shí),遠(yuǎn)程對(duì)象的 stub 程序即被傳遞出去。作為參數(shù)傳遞的遠(yuǎn)程對(duì)象僅能實(shí)現(xiàn)遠(yuǎn)程接口。

              引用的完整性

              如果一個(gè)對(duì)象的兩個(gè)引用在單個(gè)遠(yuǎn)程方法調(diào)用中以參數(shù)形式(或返回值形式)從一個(gè)虛擬機(jī)傳到另一個(gè)虛擬機(jī)中,并且它們?cè)诎l(fā)送虛擬機(jī)中指向同一對(duì)象,則兩個(gè)引用在接收虛擬機(jī)中將指向該對(duì)象的同一副本。進(jìn)一步說就是:在單個(gè)遠(yuǎn)程方法調(diào)用中,RMI 系統(tǒng)將在作為調(diào)用參數(shù)或返回值傳遞的對(duì)象中保持引用的完整性。

              類注解

              當(dāng)對(duì)象在遠(yuǎn)程調(diào)用中被從一個(gè)虛擬機(jī)發(fā)送到另一個(gè)虛擬機(jī)中時(shí),RMI 系統(tǒng)在調(diào)用流中用類的信息 (URL) 給類描述符加注解,以便該類能在接收器上加載。在遠(yuǎn)程方法調(diào)用期間,調(diào)用可隨時(shí)下載類。

              參數(shù)傳輸

              為將 RMI 調(diào)用的參數(shù)序列化到遠(yuǎn)程調(diào)用的目的文件里,需要將該參數(shù)寫入作為java.io.ObjectOutputStream 類的子類的流中。

              ObjectOutputStream 子類將覆蓋 replaceObject 方法,目的是用其相應(yīng)的 stub 類取代每個(gè)遠(yuǎn)程對(duì)象。

              對(duì)象參數(shù)將通過 ObjectOutputStream 的 writeObject 方法寫入流中。

               而ObjectOutputStream 則通過 writeObject 方法為每個(gè)寫入流中的對(duì)象(包含所寫對(duì)象所引用的對(duì)象)調(diào)用 replaceObject 方法。

             RMIObjectOutputStream子類的 replaceObject 方法返回下列值:

              如果傳給 replaceObject 的對(duì)象是 java.rmi.Remote 的實(shí)例,則返回遠(yuǎn)程對(duì)象的 stub 程序。遠(yuǎn)程對(duì)象的 stub 程序通過對(duì)java.rmi.server.RemoteObject.toStub方法的調(diào)用而獲得。

              如果傳給 replaceObject 的對(duì)象不是 java.rmi.Remote 的實(shí)例,則只返回該對(duì)象。

              RMI 的 ObjectOutputStream 子類也實(shí)現(xiàn) annotateClass 方法,該方法用類的位置注解調(diào)用流以便能在接收器中下載該類。

              有關(guān)如何使用 annotateClass的詳細(xì)信息,參見“動(dòng)態(tài)類加載”一節(jié)。

               因?yàn)閰?shù)只寫入一個(gè) ObjectOutputStream,所以指向調(diào)用程序同一對(duì)象的引用將在接收器那里指向該對(duì)象的同一副本。在接收器上,參數(shù)將被單個(gè)ObjectInputStream 所讀取。

              用于寫對(duì)象的 ObjectOutputStream(類似的還有用于讀對(duì)象的ObjectInputStream )的所有其它缺省行為將保留在參數(shù)傳遞中。例如,寫對(duì)象時(shí)對(duì) writeReplace 的調(diào)用及讀對(duì)象時(shí)對(duì) readResolve 的調(diào)用就是由 RMI的參數(shù)編組與解編流完成的。

              與上述 RMI 參數(shù)傳遞方式類似,返回值(或異常)將被寫入ObjectOutputStream的子類并和參數(shù)傳輸?shù)奶娲袨橄嗤?/p>

              定位遠(yuǎn)程對(duì)象

              我們專門提供了一種簡單的引導(dǎo)名字服務(wù)器,用于存儲(chǔ)對(duì)遠(yuǎn)程對(duì)象的已命名引用。使用類 java.rmi.Naming 的基于 URL 的方法可以存儲(chǔ)遠(yuǎn)程對(duì)象引用。客戶機(jī)要調(diào)用遠(yuǎn)程對(duì)象的方法,則必須首先得到該對(duì)象的引用。對(duì)遠(yuǎn)程對(duì)象的引用通常是在方法調(diào)用中以返回值的形式取得。RMI 系統(tǒng)提供一種簡單的引導(dǎo)名字服務(wù)器,通過它得到給定主機(jī)上的遠(yuǎn)程對(duì)象。java.rmi.Naming 類提供基于統(tǒng)一資源定位符 (URL) 的方法,用來綁定、再綁定、解開和列出位于某一主機(jī)及端口上的名字-對(duì)象對(duì)。




          盡管千里冰封
          依然擁有晴空

          你我共同品味JAVA的濃香.
          posted on 2007-08-30 11:26 千里冰封 閱讀(642) 評(píng)論(0)  編輯  收藏 所屬分類: JAVAEE
          主站蜘蛛池模板: 江油市| 克拉玛依市| 黄梅县| 宜宾市| 齐河县| 新晃| 崇信县| 肇庆市| 东城区| 孙吴县| 唐山市| 临武县| 迭部县| 莱阳市| 郑州市| 来宾市| 射洪县| 广安市| 西林县| 汉寿县| 枣阳市| 虞城县| 永春县| 桦甸市| 昌黎县| 治多县| 嘉黎县| 孝感市| 海兴县| 墨竹工卡县| 三明市| 呼和浩特市| 老河口市| 肃北| 德清县| 封开县| 吴川市| 威信县| 乌什县| 清水河县| 苍南县|