【Java基礎】第九講 JavaBean和RMI

【課前思考】
  1. 什麼是JavaBean?
  2. JavaBean和Java有什麼關係?
  3. JavaBean會有什麼樣的用途?
  4. 什麼是RMI?
  5. RMI技術會有什麼樣的特點?
  6. 什麼是EJB?
  7. EJB和JavaBean又有什麼樣的關係?

9.1 JavaBean的基本概念
9.1.1 JavaBean產生的背景介紹

軟件組件就是指可以進行獨立分離、易於重複使用的軟件部分。JavaBean就是一種基於Java平臺的軟件組件思想。JavaBean也是一種獨立於平臺和結構的應用程序編程接口(API)。JavaBean保留了其他軟件組件的技術精華,並增加了被其他軟件組件技術忽略的技術特性,使得它成爲完整的軟件組件解決方案的基礎,並在可移植的Java平臺上方便地用於網絡世界中。

9.1.2 JavaBean基本概念

雖然JavaBean和Java之間已經有了明確的界限,但是在某些方面JavaBean和Java之間仍然存在很容易混淆的地方,比如說重用,Java語言也可以爲用戶創建可重用的對象,但它沒有管理這些對象相互作用的規則或標準,用戶可以使用在Java中預先建立好的對象,但這必須具有對象在代碼層次上的接口的豐富知識。而對於JavaBean,用戶可以在應用程序構造器工具中使用各種JavaBean組件,而不需要編寫任何代碼。這種同時使用多個組件而不考慮其初始化情況的功能是對當前Java模型的重要擴展,所以也可以說JavaBean是在組件技術上對Java語言的擴展。
  如果真的要明確的定義,那麼JavaBean的定義是:JavaBean是可複用的平臺獨立的軟件組件,開發者可以在軟件構造器工具中對其直接進行可視化操作。在上面的定義中,軟件構造器可以是Web頁面構造器、可視化應用程序構造器、GUI設計構造器或服務器應用程序構造器。而JavaBean可以是簡單的GUI要素,如按鈕和滾動條;也可以是複雜的可視化軟件組件,如數據庫視圖。有些JavaBean是沒有GUI表現形式的,但這些JavaBean仍然可以使用應用程序構造器可視化地進行組合,比如JBuilder上的很多控件其實也是沒有GUI形式的,但是你仍然可以拖放它們以在你的應用程序裏生成相應的代碼。一個JavaBean和一個Java Applet很相似,是一個非常簡單的遵循某種嚴格協議的Java類。
 
 JavaBean具有Java語言的所有優點,比如跨平臺等等,但它又是Java在組件技術方面的擴展,所以說很多方面它和Applet很像,Applet也具有Java語言的所有優點,同時也是Java在瀏覽器端程序方面的擴展。其實它們都是嚴格遵循某種協議的Java類,它們的存在都離不開Java語言的強大支持。

9.1.3 JavaBean的屬性、事件和方法

從基本上來說,JavaBean可以看成是一個黑盒子,即只需要知道其功能而不必管其內部結構的軟件設備。黑盒子只介紹和定義其外部特徵和與其他部分的接口,如按鈕、窗口、顏色、形狀等。作爲一個黑盒子的模型,以把JavaBean看成是用於接受事件和處理事件以便進行某個操作的組件建築塊。

一個JavaBean由3部分組成:
   (1) 屬性(properties)
  JavaBean提供了高層次的屬性概念,屬性在JavaBean中不只是傳統的面向對象的概念裏的屬性,它同時還得到了屬性讀取和屬性寫入的API的支持。屬性值可以通過調用適當的bean方法進行。比如,可能bean有一個名字屬性,這個屬性的值可能需要調用String getName()方法讀取,而寫入屬性值可能要需要調用void setName(String str)的方法。
  每個JavaBean屬性通常都應該遵循簡單的方法命名規則,這樣應用程序構造器工具和最終用戶才能找到JavaBean提供的屬性,然後查詢或修改屬性值,對bean進行操作。JavaBean還可以對屬性值的改變作出及時的反應。比如一個顯示當前時間的JavaBean,如果改變時鐘的時區屬性,則時鐘會立即重畫,顯示當前指定時區的時間。
  (2) 方法(method)
  JavaBean中的方法就是通常的Java方法,它可以從其他組件或在腳本環境中調用。默認情況下,所有bean的公有方法都可以被外部調用,但bean一般只會引出其公有方法的一個子集。
  由於JavaBean本身是Java對象,調用這個對象的方法是與其交互作用的唯一途徑。JavaBean嚴格遵守面向對象的類設計邏輯,不讓外部世界訪問其任何字段(沒有public字段)。這樣,方法調用是接觸Bean的唯一途徑。
  但是和普通類不同的是,對有些Bean來說,採用調用實例方法的低級機制並不是操作和使用Bean的主要途徑。公開Bean方法在Bean操作中降爲輔助地位,因爲兩個高級Bean特性--屬性和事件是與Bean交互作用的更好方式。
  因此Bean可以提供要讓客戶使用的public方法,但應當認識到,Bean設計人員希望看到絕大部分Bean的功能反映在屬性和事件中,而不是在人工調用和各個方法中。
  (3) 事件(event)
  Bean與其他軟件組件交流信息的主要方式是發送和接受事件。我們可以將bean的事件支持功能看作是集成電路中的輸入輸出引腳:工程師將引腳連接在一起組成系統,讓組件進行通訊。有些引腳用於輸入,有些引腳用於輸出,相當於事件模型中的發送事件和接收事件。
  事件爲JavaBean組件提供了一種發送通知給其他組件的方法。在AWT事件模型中,一個事件源可以註冊事件監聽器對象。當事件源檢測到發生了某種事件時,它將調用事件監聽器對象中的一個適當的事件處理方法來處理這個事件。

9.1.4 JavaBean的特徵

JavaBean1.0指定的組件模型規定了Bean的如下特徵:
  (1)內省:使組件可以發表其支持的操作和屬性的機制,也是支持在其他組件中(如Bean的開發工具)發現這種機制的機制。
  (2)屬性:在設計Bean時可以改變的外觀和行爲特徵。開發工具通過對Bean進行內省來獲知其屬性,進而發佈其屬性。
  (3)定製:Bean通過發佈其屬性使其可以在設計時被定製。有兩種方法支持定製:通過使用Beans的屬性編輯器,或者是使用更復雜Bean定製器。
  (4)通信:Bean之間通過事件互相通信。開發工具可以檢測一個Bean可以接收和引發的事件。
  (5)持續:使Bean可以存儲和恢復其狀態。一個Bean的屬性被修改以後,可以通過對象的持續化機制保存下來,並可以在需要的時候恢復。
9.1.5 JavaBean特徵實現的簡介

1 屬性
  Bean的屬性描述其外觀或者行爲特徵,如顏色、大小等。屬性可以在運行時通過get/set方法取得和設置。最終用戶可以通過特定屬性的get/set方法對其進行改變。例如,對於Bean的顏色屬性,最終用戶可以通過Bean提供的屬性對話框改變這個顏色屬性。顏色的改變實際上是通過下面的方法實現的:
    public Color getFillColor();
    public void SetFillColor(Color c);
  這種基本的get/set方法命名規則定義的屬性叫做簡單屬性。簡單屬性中有一類用boolean值表示的屬性叫布爾屬性。
  JavaBean API還支持索引屬性,這種屬性與傳統Java編程中的數組非常類似。索引屬性包括幾個數據類型相同的元素,這些元素可以通過一個整數索引值來訪問,因此稱爲索引屬性。屬性可以索引成支持一定範圍的值,這種屬性屬於簡單屬性。索引用int指定。索引屬性有4種訪問方式,其數值數組可以一個元素訪問,也可以整個數組訪問:

    public void setLabel(int index,String label);
    public String getLabel(int index);
    public void setLabel(String []labels);
     public String []getLabels();
  與標準的Java數組類似索引值可能會在索引屬性數組的範圍之外。這時,用於操作索引屬性的訪問者方法一般是拋出一個ArrayIndexOutOfBoundsException運行環境異常,這個異常與標準Java數組索引超出範圍時執行的行爲相同。
  與簡單屬性相對的是關聯屬性和限制屬性。這兩種屬性在運行或者設計時被修改後,可以自動地通知外部世界,或者有能力拒絕被設置爲某個數值的屬性。關聯屬性在屬性發生改變時向其他beans和容器發出通知。關聯屬性在發生改變時產生一個PropertyChangeEvent事件,傳遞給所關聯的註冊了PropertyChangeListener的聽衆。可以通過下述方法註冊或撤銷多路廣播事件聽衆:
   public void addPropertyChangeListener(PropertyChangeListener l);
   public void removePropertyChangeListener(PropertyChangeListener l);
  PropertyChangeListener是一個接口,當相關的外部部件需要與一個屬性相關聯時,它必須調用addPropertyChangeListener()方法提供一個合適的實現了PropertyChangeListener接口的對象。PropertyChangeListener接口用於報告關聯屬性的修改,尤其是當一個關聯屬性值發生變化時,就調用所有註冊的PropertyChangeListener接口上的propertyChange()方法。這個方法接受一個PropertyChangeEvent對象,這個對象包含了關於要修改的特定屬性的信息及其新值和舊值。
  JavaBean API還支持另一種方法用於註冊監聽器與特定的關聯屬性。如果一個bean開發者要在單個屬性基礎上提供監聽器註冊,他必須爲每個這樣的屬性支持一對方法:add<PropertyName>Listener()和remove<PnropertyName>Listener()。這對方法工作起來就像前面介紹的那對全局事件監聽器註冊方法,只是這兩個方法是用於特定的屬性。下面的一個例子中定義了一個名爲Name的關聯屬性的這兩個方法:
    public void addNameListener(PropertyChangeListener l);
    public void removeNameListener(PropertyChangeListener l);
  當bean外部相關部件要將其本身註冊到Name屬性上時,它只需簡單地調用addNameListener()方法來註冊它本身。當Name屬性修改時,會通過調用propertyChange()方法發送一個通知給事件監聽器。這種情況與前面介紹的一樣,只是這裏的監聽器只接收關於Name屬性的通知。
  限制屬性是內部驗證的,如果不合格會被拒絕。用戶可以通過異常獲知拒絕的屬性。限制屬性用VetoableChangeListener接口驗證改變。可以用如下方法註冊或撤銷該接口:
    public void addVetoableChangeListener(VetoableChangeListener v);
    public void removeVetoableChangeListener(VetoableChangeListener v);
  限制屬性和關聯屬性的處理機制是很類似的,當屬性的修改值到達監聽器的時候,監聽器可以通過拋出PropertyVetoException異常選擇拒絕屬性的修改。如果拋出了一個異常,這個bean就要負責處理這個異常並恢復這個限制屬性的原來的值。
  與關聯屬性類似,限制屬性也支持單個屬性的事件監聽方法。下面是一個例子:
    public void addNameListener(VetoableChangeListener l);
    public void removeNameListener(VetoableChangeListener l);
 
2 內省和定製
  
Bean通常被開發成一般化的組件,由開發人員在建立應用程序時配置。這是通過JavaBeans API伴隨的兩種Java技術實現的。第一種是Java反映API,是一組用於透視類文件和顯示其中的屬性和方法的類。第二種是Java串行化API,用於生成類的永久存儲,包括其當前狀態。這兩種技術用於使Beans可以用建立工具探索和顯示,並修改和存放起來,供特定應用程序使用。

  JavaBean的內省過程顯示Bean的屬性、方法和事件。內省過程實際上很簡單,如果有設置或取得屬性類型的方法,則假設Bean有該屬性,可以採用如下方法:
    public <PropertyType> get<PropertyName>();
    public void set<PropertyName>(<PropertyType> p);
  如果只發現一個get/set方法,則確定PropertyName爲只讀或只寫。
  除了上述這種內置的內省和定製方法外,JavaBean API還提供了顯示的接口BeanInfo,用於Bean設計者顯示Bean的屬性、事件、方法和各種全局信息。可以通過實現BeanInfo接口定義自己的Bean信息類:
    public class myBeanInfo implements BeanInfo..
  BeanInfo接口提供了一系列訪問Bean信息的方法,Bean開發者還可以提供BeanInfo類用於定義Bean信息的專用描述文件。
 
3 持續

  JavaBean是依賴於狀態的組件,狀態可能因爲運行時或開發時的一些動作而發生改變,當Bean的狀態改變時,設計人員可以保存改變的狀態,這種機制叫JavaBean的持續。
  JavaBean狀態的持可以通過java對象的串行化機制自動保存,也可以由設計者通過定製其串行化控制Bean對象的狀態的保存。

 4 事件
  JavaBean通過傳遞事件在Bean之間通信。Bean用一個事件告訴另一個Bean採取一個動作或告訴其狀態發生了改變。事件從源聽衆註冊或發表並通過方法調用傳遞到一個或幾個目標聽衆。
  JavaBean的事件模型類似AWT的事件模型。JavaBean中的事件模型是用事件源和事件目標定義的。事件源就是事件的啓動者,由它觸發一個或多個事件目標。事件源和事件目標建立一組方法,用於事件源調動事件聽衆。
9.2.3 JavaBean的開發工具簡介

1 Borland公司的JBuilder
  使用JBuilder,開發者可以使用任何包括在這個產品中的或是從第三方供應商購買的JavaBean組件迅速地開發出應用程序,也可以使用JBuilder的可視化設計工具和wizard創建自己的可複用的JavaBean組件。JBuilder含有功能強大的JavaBean數據庫組件,它可以滿足創建與數據庫有關的應用程序的需求。另外,JBuilder提供了Java優化工具集爲專業Java開發者提供了綜合的、高性能的開發解決方案。JBuilder的基於組件開發環境的幾個主要子系統,包括組件設計器和雙向工具引擎,都是使用JavaBean內置於Java中的。
   
關於JBuilder的更多信息,可以訪問Borland公司的Web站點:
   
http://www.borland.com/jbuilder

 
2 IBM公司的Visual Age for Java
  IBM的Visual Age for Java的發佈使得客戶/服務器系統的Internet應用程序的實現成爲現實。這個工具將Java的快速開發環境與可視化編程結合在一起。Visual Age for Java是一個創建可與Java兼容的應用程序、applet和JavaBean組件的編程環境,它使得開發者可以將注意力集中在應用程序的邏輯設計上。Visual Age for Java可以幫助開發者實現許多應用程序中經常需要的任務,如通訊代碼、在企業級上進行Web連接以及用戶接口代碼的創建。
  
關於Visual Age for Java的更詳細的信息可以查看Web站點:
  
http://www.software.ibm.com/ad/vajava

 
3 SunSoft公司的Java Studio
  Java Studio是一個可視化組裝工具,一個"所見即所得"的HTML創作工具和一個完全使用Java編寫的可重複使用的組件開發工具。Java Studio使用的JavaBean技術包含了一個豐富而強壯的商業組件集合,包括圖表、曲線以及通過窗體和電子表格等支持的數據庫訪問和操作。此外,還包括用於創建網絡軟件輔助組件。輔助組件包括電子表格、白板和聊天組件。
  
Java Studio的web網址位於:
  
http://www.sun.com/studio/
9.2.4 使用BeanBox測試JavaBean

BDKBeans Developmen Kit)是Sun公司發佈的Beans開發工具箱,它與JDK配合使用,可以生成使用Bean事件模型的BeansBDK的使用依賴於JDKBeanBoxBDK中自帶的一個用於測試Beans的工具,可以用它可視地管理Beans的屬性和事件。BeanBox並不是一個建立Beans的工具,它只是一個測試工具,我們可以通過它來了解Beans

9.3 RMI的基本概念和編程簡介
9.3.1 RMI的基本概念

Java RMIRemote Method Invocation--Java的遠程方法調用是Java所特有的分佈式計算技術,它允許運行在一個Java虛擬機上的對象調用運行在另一個Java虛擬機上的對象的方法,從而使Java編程人員可以方便地在網絡環境中作分佈式計算。面向對象設計要求每個任務由最適合該任務的對象執行,RMI將這個概念更深入了一步,使任務可以在最適合該任務的機器上完成。

RMI定義了一組遠程接口,可以用於生成遠程對象。客戶機可以象調用本地對象的方法一樣用相同的語法調用遠程對象。RMI API提供的類和方法可以處理所有訪問遠程方法的基礎通信和參數引用要求的串行化。

遠程方法調用類似於Sun公司1985年提出的遠程過程調用(RPC)特徵。RPC也要求串行化參數和返回數值數據,但由於沒有涉及對象,情況比較簡單。Sun開發了外部數據表示(XDR)系統,支持數據串行化。RPCRMI之間的一個重要差別是RPC用快速而不夠可靠的UDP協議,RMI用低速而可靠的TCP/IP協議。
  遠程方法調用(RMI)和CORBA都是分佈式計算技術,在進行分佈式時各有其優缺點,爲了有助於瞭解RMI的特點和用途,有必要討論一下CORBARMI的區別。
  CORBACommon Object Request Broker Architecture)是OMGObject Management Architecture(對象管理結構),它是面向對象的分佈式系統建立所依據的標準。CORBA被設計成一個能供所有編程語言使用的一個開放性說明,就是說一個機器上的Java客戶可以要求另一個用SmallTalkC++的機器服務。正是由於這種語言的獨立性使得CORBA這麼靈活和吸引人。爲了適應語言獨立性,CORBA採用了非常通用的標準作爲其接口。在不同的語言中,遠程調用、簽名和對象的引入有各自不同的定義,所以CORBA必須儘可能的中立和開放。正是這種通用性是CORBA的一個弱點。當開發人員都採用CORBA時,他們要用一種新的標準定義語言接口,它要求開發者學習新的編程接口,從而減小了遠程模型的透明性。
  RMI是爲僅在JavaJava的分佈式計算中而開發的。遠程調用的標準是爲了Java和應用Java的自然Java簽名和調用而開發的,這使得RMIJava的開發者相當透明而且易於實現。RMIJava語言緊密集成從而同CORBA相比能夠提供非常好的容錯能力及對異常的處理。儘管JavaRMI標準不像CORBA那樣語言獨立,但Java本身是一個獨立的平臺,這就使RMI在跨平臺的分佈軟件開發中是一個很好的選擇。
  RMIJava語言在分佈式計算上的基本模型,很多Java的分佈式系統,包括我們本章要涉及的EJB,都是建立在RMI的思想上的。
9.3.2 RMI系統的一般結構

RMI系統包括3層,端頭/框架層(Stubs/Skeletons)、遠程應用層(Remote Reference Layer)和傳送層(Transport,如圖所示:

  客戶機調用遠程方法時,請求用客戶機的端頭調用。客戶機引用端頭作爲遠程機上對象的代表。上圖所示的所有基礎功能在客戶機上都看不到。端頭代碼由rmic編譯器長生,並用遠程引用層(RRL)將方法調用請求傳遞到服務器對象。

9.3.3使用RMI構造分佈式應用系統

RMI應用程序通常由兩個獨立的程序構成:一個server和一個client。一個典型的server應用程序創建一些遠程對象,使它們可被引用,並等待客戶端調用這些遠程對象的方法。一個典型的client應用程序得到server上的一個或多個遠程對象的遠程引用,並調用這些對象的方法。RMI提供了serverclient通信和傳遞信息的機制。這樣的應用程序叫做一個分佈式對象應用程序。
  分佈式對象應用程序需要定位遠程對象:應用程序可以使用兩種機制之一來獲得遠程對象的引用。應用程序可以使用RMI的命名工具rmiregistry來註冊它的遠程對象,或者象進行一般操作一樣傳遞和返回遠程對象的引用。
  和遠程對象通信:遠程對象之間的通信細節由RMI來處理。對程序員來說,遠程通信就像一個標準的Java方法調用。
  裝載被傳遞對象的類字節碼:因爲RMI允許調用者向遠程對象傳遞對象,所以它提供了傳遞數據和裝載一個對象代碼的必要機制。
  下圖描述了一個使用註冊機制獲得一個遠程對象引用的RMI分佈式應用程序。Server方調用註冊器將一個遠程對象和一個名字聯繫起來。Client方在Server的註冊器中通過名字尋找遠程對象並調用其方法。該圖也顯示了RMI系統使用一個現有web server來裝載類字節碼,在需要時在serverclient之間傳輸字節碼。

RMI的一個重要而獨特的特性是它能動態下載一個在接收者的虛擬機中未定義的對象類的字節碼(或簡單代碼)。一個對象的類型和行爲,這些原來只能在一個單一的虛擬機中可以得到的信息,可以被傳遞給另一個可能是遠程的虛擬機。RMI將對象連同其真實的類型一起傳遞,所以當這些對象被傳遞給另一個虛擬機時其行爲不發生改變。這就允許將新類型引入一個遠程的虛擬機,從而動態擴展一個應用程序的行爲。
  像其他應用程序一樣,一個使用Java RMI的分佈式應用程序也由接口和類組成。接口中定義一些方法,類實現接口中定義的方法,並定義一些其他的方法。在一個分佈式應用程序中,一些實現需要駐留在不同的虛擬機上。具有可以跨虛擬機調用的方法的對象叫做遠程對象。一個對象通過實現一個遠程接口成爲遠程對象,它具有如下特徵:
  1 一個遠程接口由java.rmi.Remote派生。
  2 接口中的每個方法都要聲明拋出java.rmi.RemoteException,除了 其他特殊的例外之外。
  當對象從一個虛擬機傳遞給另一個虛擬機時,RMI對遠程對象的處理與非遠程對象是不相同的。於遠程對象,RMI傳遞給接收方虛擬機一個遠程端頭,而不是一個對象的拷貝。端頭作爲遠程對象的本地標識或代理,對於調用方來說,是一個遠程引用。調用方調用本地端頭的一個方法,由本地端頭負責處理對遠程對象的方法調用。
  一個遠程對象的端頭實現了與遠程對象實現的相同的接口。這就允許一個端頭可以被轉換爲遠程對象所實現的任意一個接口。這也意味着只有定義在遠程接口中的方法纔可以在接收方虛擬機上被調用。

  當你使用RMI來開發一個分佈式應用時,需要遵守下面的步驟:
  1 設計和實現你的分佈式應用的組件。
  首先,決定應用程序的結構,哪些組件是本地對象,哪些應該可以遠程訪問。這個步驟包括:
  定義遠程接口:一個遠程接口定義了可以被客戶端遠程調用的方法。客戶端針對遠程接口編程,而不是針對實現這些接口的類。設計這樣的接口的一部分工作取決於作爲這些方法的參數和返回值的本地對象。如果還沒有這樣的接口和類的存在,就需要自己定義。
  實現遠程對象:遠程對象必須實現一個或多個遠程接口。遠程對象類可能包括其他接口(本地的或遠程的)和方法(僅在本地可得到的)的實現。如果有本地類作爲這些方法的參數或返回值,這些類也必須被實現。
   
實現客戶端:使用遠程對象的客戶可以在遠程接口被定義後的任何時候實現,包括遠程對象被展開後。
  2 編譯源程序並生成端頭。  
  這是一個兩步操作過程。第一步,使用Javac編譯器來編譯源文件,其中包含了遠程接口及其實現部分、server類和client類。第二步,使用rmic編譯器來生成遠程對象的端頭。RMI使用一個遠程對象的端頭類來作爲客戶端的代理,從而使客戶端可以同一個特定的遠程對象通信。
  3 使得類可以通過網絡訪問。
  這一步使一切與遠程接口有關的類文件、端頭、其他任意的需要下載到客戶方的類可以通過一個web server訪問。
  4 啓動應用程序。
  啓動應用程序包括運行RMI遠程對象註冊程序,服務器,客戶端。

9.3.4 一個簡單的RMI的例子
  一個雖然簡單但是完整的RMI分佈式應用程序的例子,該程序由兩部分組成;包括遠程對象的server方和調用server方的遠程方法sayHello()獲得字符串"Hello World"並輸出該字符串的client方。

1 構造一個遠程接口Hello
  package hello;
  public interface Hello extends java.rmi.Remote {
  //rmi應用程序必須繼承自java.rmi.Remote
    String sayHello() throws java.rmi.RemoteException ;
    //定義可以遠程調用的接口
  }
 2 完成server方程序,定義HelloImpl類實現Hello接口:

package hello;
  import java.rmi.*;
  import java.rmi.server.UnicastRemoteObject;
  public class HelloImpl extends UnicastRemoteObject implements Hello
                     //實現Hello接口
  {
    private String name;
    public HelloImpl (String s ) throws java.rmi.RemoteException{
    super(); //調用父類的構造函數
    name = s;
  }
  public String sayHello() throws RemoteException {
    return "Hello world!"; //實現Hello接口定義的方法
  }
  public static void main ( String args [])
  {
    System.setSecurityManager ( new RMISecurityManager() );
    //設置RMI程序需要的安全策略
    try
    {
     HelloImpl obj = new HelloImpl("HelloServer");
     //生成一個HelloImpl的實例
     Naming.rebind("HelloServer", obj);
     //將這個實例綁定到一個名字上
     System.out.println("HelloImpl created and bound in the registry to the name HelloServer");
    } catch (Exception e)
    {
     System.out.println("HelloImpl.main: an exception occured:");
     e.printStackTrace(); //產生異常的話,打印出出錯信息
    }
  }
}
  server方生成一個遠程對象並和一個可和客戶對話的名稱"HelloServer"綁定。Client端可以根據該名稱尋找相應的遠程對象,進而調用其遠程方法。
 3 完成client方程序
  package hello;
  import java.rmi.*; public class HelloClient
  {
   public static void main(String args[])
  {
   System.setSecurityManager(new RMISecurityManager() );
   //設置RMI需要的安全策略
   try
   {
    Hello obj = (Hello) Naming.lookup("HelloServer");
    //從服務端獲得一個Hello的遠程對象
    String message = obj.sayHello();
    //遠程調用Hello的方法
    System.out.println(message);
    //將輸出結果打印
   } catch (Exception e)
   {
    System.out.println("Hello client : an exception occured");
    e.printStackTrace(); //若有異常,輸出異常信息
   }
  }
}

  client利用java.rmi包中的Naming類的lookup()方法獲得遠程對象obj,然後調用其遠程方法sayHello()獲得字符串"Hello World",並輸出到屏幕上。
  要運行這幾個程序,還有一些工作要做,這幾個程序的文件名爲Hello.javaHelloImpl.javaHelloClient.java,它們都被放置在的的d:/hello目錄下,在windows下,你需要在命令窗口中如此運行它們:

1 Set CLASSPATH = %CLASSPATH%;d:/
  2 d:/hello下編譯源代碼:
    javac -d .. *.java
  3 在生成端頭和框架模塊,首先把目錄切換回d:/
    rmic -d . hello.HelloImpl
  4 d:/下運行RMI遠程對象註冊程序
    start rmiregistry
  5 d:/下運行服務器程序
    java -Djava.security.policy=my.policy hello.HelloImpl
  6 d:/下運行客戶端程序
    java -Djava.security.policy=my.policy hello.HelloClient
  其中上面的步驟中56出現的my.policy是一個文件,這個文件和Java的安全機制有關,在這個程序中我們不需要安全限制,所以我們把權限設爲都可以訪問。my.policy如下:
  grant {
      permission java.security.AllPermission;
  };
  你一定要記得設置這個文件,否則RMI將出"拒絕訪問"的錯誤。如果你想了解Java其他的安全機制,那麼可以參考Java裏有關security的資料。

9.4 EJB簡介
9.4.1 EJB出現的背景
  EJB的出現對Java技術是一個很大的推動,因爲EJB主要是面向企業級應用的,這使得Java有了企業級應用的方向。同樣,EJB也是建立在Java語言上的,和JavaBeanJava Applet一樣,它也是遵守一定規範的Java程序,只不過這是個複雜的規範。

傳統的分佈式應用程序都是基於Client/Server結構的,而近年來人們發現基於Client/Server結構的應用程序有很多缺點,比如:如果客戶端的代碼需要改變,那麼所有機器上的客戶端程序都要重新安裝;如果某臺機器有了不可修復的損壞,那麼得去別的機器上重新安裝客戶端軟件才能夠使用。而基於Browser/Server結構的應用程序就沒有以上的缺點了,我們可以使用任何一臺有瀏覽器的機器來工作,而因爲所有的程序邏輯都在服務器端,所以服務器端的代碼變動不需要作爲客戶端的瀏覽器再做任何工作。
  由於Browser/Server結構的這些優勢,近年來關於Browser/Server的程序開發模式有了很多的研究和實踐。而因爲Browser沒有辦法表示複雜的程序邏輯,所以在表示界面的Browser和存儲介質數據庫之間必須還有一層結構,這層結構負責表示複雜的程序邏輯。這就是我們所說的服務器端構件,在Brower/Server結構中,我們的工作就是開發服務器端構件,但是開發服務器端構件是很麻煩的工作。因爲服務器端構件必須接受很多客戶端的請求,因此它必須具有多線程和事務處理等能力,而這些也成爲服務器端構件開發的難點所在。

9.4.2 EJB的概要
  事實上EJBJava在企業級應用的規範,所以EJB還是比較複雜的,EJB只是組件的規範,而爲了讓EJB跑起來還需要很多其他的東西,比如說容器,應用程序服務器等,這些都是和EJB緊密聯繫在一起的,而因爲EJB一般用於Web應用中,所以還需要一個Web服務器,而EJB的客戶端也可以是任何的Java程序,比如AppletServlet等等,所以EJB只是企業級應用平臺中的一部分,而這個企業級應用平臺就是SunJ2EEJava 2 Enterprise Edition)。而上面我們提到的WeblogicWebsphere其實都是符合J2EE的企業級應用平臺。

Sun公司發佈的文檔中對EJB的定義是:EJB是用於開發和部署多層結構的、分佈式的、面向對象的Java應用系統的跨平臺的構件體系結構。採用EJB可以使得開發商業應用系統變得容易,應用系統可以在一個支持EJB的環境中開發,開發完之後部署在其他的EJB環境中,隨着需求的改變,應用系統可以不加修改地遷移到其他功能更強、更復雜的服務器上。

EJB簡化了多層體系結構應用系統的開發過程。在分佈式應用系統的開發中,採用多層體系結構的方法有很多優點,如增加了應用系統的可伸縮性、可靠性、靈活性等。因爲服務器端構件可以根據應用需求加以修改,且構件在網絡中的位置和應用無關,因此係統管理員可以很容易重新配置系統的負載。多層體系結構非常適合於大數據量的商業事務系統,特別是在基於Web的應用中,需要多層體系結構支持瘦客戶機及瀏覽器的快速Applet下載,目前越來越多的系統開始採用多層體系結構的方法,所謂的多層結構,可以用下圖來幫助理解:

  在多層結構中,數據庫算是一層,客戶端算一層,而客戶端和數據庫之間統稱爲N-2層,N-2層主要是表示程序的邏輯。EJB的作用就是在這N-2層裏面負責表示程序的邏輯和提供訪問數據庫的接口EJB分爲兩類,一類是實體BeanEntity Bean),這種EJB和數據庫中的表有一一對應的關係,可以在數據改變的時候自動更新表裏的內容。還有一類是對話BeanSession Bean),這種EJB用於和客戶端交互,代表了程序的邏輯,我們可以用這兩種EJB來方便的構建自己的多層系統。
  EJBJava"write once run anywhere"思想提到了一個新的高度,服務器端構件在構件執行系統內執行,規範說明定義了構件執行系統所需要的服務,遵從EJB規範說明開發的構件可以在任何一個支持EJB的系統中執行。EJB其實是在容器裏執行的,Sun公司也發佈了EJB容器的規範,EJB可以在任何符合規範的容器中運行,容器其實就是給EJB提供服務的,比如說EJB需要的事務處理,多線程和安全機制等服務。

9.4.3 EJB的軟構件模型簡介
  JavaBean也是構件,只不過它不是服務器端的構件,在構件中我們稱JavaBean是輕量級的,而EJB是重量級的。

軟構件模型的思想是創建可重用的構件並將其組合到容器中以得到新的應用系統構件模型定義了構件的基本體系結構、構件界面的結構、和其他構件及容器相互作用的機制等。利用構件模型的規範說明,構件開發人員開發那些實現了應用程序邏輯的構件,而應用系統開發人員把這些預先開發好的構件組合成應用系統,這些應用系統也可以作爲新的構件。軟構建模型思想已經在軟件開發界迅速流行,因爲它可以達到以下這些目的:重用、高層開發、通過工具進行自動化開發、簡化開發過程等。JavaBeansEJBCOM/DCOM等都是軟構件模型的例子。
  有兩種類型的軟構件模型--客戶端構件模型和服務器端構件模型。客戶端構件模型如JavaBeans是專門用於處理程序的表示(presentation)及用戶界面問題的;服務器端構件模型如EJB則向面向事務的中間件提供基礎設施。
  服務器端構件模型把構件模型的開發和中間件聯繫在一起。企業級應用的中間件以其複雜性著稱,它不僅涉及到應用邏輯、併發性和伸縮性問題,也涉及到如何把不兼容的系統組合在一起的問題。服務器端構件模型解決了中間件開發的複雜性問題,它使得中間件開發人員集中於應用系統的邏輯部分,而不用處理同步、可伸縮性、事務集成、網絡、分佈式對象框架等一些分佈式應用系統中存在的複雜問題EJB構件模型如下圖所示:

EJB構件模型給開發者提供了一下的支持:
  1 構件包含應用程序邏輯
  2 可重用的構件
  3 可伸縮性
  4 資源管理
  5 事務支持
  6 併發性管理
9.4.4 EJB和其他技術的關係

1EJBJavaBean的關係
  很多人往往把JavaBeanEJB混淆起來,JavaBean提供了基於構件的開發機制,一般JavaBeans是可視化的構件,也有一些JavaBeans是非可視化的,JavaBeans可以在多個應用系統中重用,一個標準的JavaBeans是一個客戶端構件,在運行時不能被其他客戶機程序存取或操作,但客戶端的JavaBeans容器可以根據JavaBeans的屬性、方法、事件的定義在設計或運行時對JavaBeans進行操作,JavaBeans不一定要用於Client/Server結構的系統。
  EJB沒有用戶界面,完全位於服務器端EJB可以多個JavaBean組成,規範說明詳細說明了EJB容器需要滿足的需求以及如何和EJB構件相互協作。EJB可以和遠程客戶端程序通信,並提供一定的功能,根據規範說明,EJBClient/Server系統的一部分,如果不和客戶端程序交互,EJB一般不執行具體的功能。EJBJavaBean的一個重要區別是EJB提供了網路功能
2EJBRMI的關係
  EJB是分佈式的組件,它支持遠程調用。而EJB的這些網絡特性是建立在RMI之上的,可以說,RMIEJB網絡特性的基石。
  因爲EJB是分佈式的,所以如何定位一個EJB也是需要解決的問題,而這個問題和RMI裏如何定位一個對象是一樣的,EJB也用了RMI registry的思想,EJB裏的JNDIJava Naming and Directory Interface)也提供了註冊一個對象的服務,已經註冊了的對象可以很容易的被找到。這和RMIregistry的想法和功能上是一樣的。
3 EJB和網絡計算的關係
  Beans構造的應用程序可以根據用戶的需求分解成不同的構件,根據用戶當前所需要的功能提供相關的構件,並隨着用戶新的需求隨時下載新的構件,而用戶沒有用到其功能的構件可以駐留在服務器上,這就是網絡計算所倡導的概念。
  很多人並沒有完全理解Java的概念,他們認爲爲了在一個客戶端上運行Java程序,需要把一個龐大的、可能達幾兆字節的Java應用程序一次性通過網絡傳輸到客戶端,事實上,這也是一些開發人員計劃用Java改寫舊的應用系統時易犯的錯誤。
  在網絡計算環境中利用Java的最好途徑是由EJB提供服務端的構件,而由JavaBeans提供客戶端的構件,兩者結合在一起,將會使應用系統的搭建更爲簡單和快速。
  只有把Java應用於服務器端的應用系統才能真正體現Java的威力,EJBJava的服務器端構件模型,該模型保證開發出來的構件可以被部署在任何支持EJB規範說明的系統中,既使該系統是由不同的開發商提供的。採用EJB可以提高開發人員的生產率,構件開發人員和應用開發人員不需要實現系統中的一些複雜的邏輯結構,因爲構件的容器已提供對這些服務的自動管理和控制,採用EJB開發的應用系統不用修改就可以從一個服務器遷移到另一個功能更強的服務器上。
  總之,EJB技術將使得Java在企業計算中的地位得到加強,爲基於Java的應用系統提供了一個框架,和目前的許多系統和模型相比,EJB具有許多優越性,種種跡象表明,EJB有可能成爲分佈式應用系統的服務器端構件模型的首要選擇。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章