與現有服務器的連接 人們常說
RMI主要是
從Java到Java
但這種說法掩蓋了這樣一個事實
Java可使用被稱為JNI的本機方法接口
很容易地與現有和原有系統連接
JNI和RMI的混合使用與任何其它Java程序一樣簡單
您可使用JDBC
再結合RMI
與現有的關系數據庫連接
也就是說
您可使用RMI連接二層次和三層次系統
即使雙方都不是用Java 編寫的亦可
這樣做有很大的好處和優勢
下面會詳細闡述
但首先讓我們看一看它是如何完成的
假定您現在有一台在關系數據庫中存儲了有關客戶訂單信息的服務器
在任何多層次系統中
您都得設計一個遠程接口
以便於客戶機訪問服務器
利用作為Remote 接口的RMI
import java
rmi
*;
import java
sql
SQLException;
import java
util
Vector;
public interface OrderServer extends Remote {
Vector getUnpaid() throws RemoteException
SQLException;
void shutDown() throws RemoteException;
//
other methods (getOrderNumber
getShipped
)
}
java
sql包包含JDBC包
每個遠程方法均可被服務器采用實際數據庫的JDBC調用
或通過采用其它數據庫訪問機制的本機方法實現
上面所示的方法返回一個Order (訂單) 對象的Vector (列表)
Order (訂單)就是在您的系統中定義的
用來保存客戶訂單的類
本節將介紹如何使用JDBC實現getUnpaid
和如何使用JNI 實施shutDown
JDBC 連接數據庫 使用JDBC實現getUnpaid的OrderServerImpl如下
import java
rmi
*;
import java
rmi
server
*;
import java
sql
*;
import java
util
Vector;
public class OrderServerImpl
extends UnicastRemoteObject
implements OrderServer
{
Connection db; // connection to the db
PreparedStatement unpaidQuery; // unpaid order query
OrderServerImpl() throws RemoteException
SQLException {
db = DriverManager
getConnection(
jdbc:odbc:orders
);
unpaidQuery = db
preparedStatement(
…
);
}
public Vector getUnpaid() throws SQLException {
ResultSet results = unpaidQuery
executeQuery();
Vector list = new Vector();
while (results
next())
list
addElement(new Order(results));
return list;
}
public native void shutDown();
}
其中大多是JDBC任務
除了以Order開始的類型是您的系統的一部分類型以外
您所看到的所有類型均為JDBC或 RMI的一部分
構造函數初始化OrderServerImpl對象
創建與jdbc URL中所規定的數據庫的連接( Connection)
有了這個連接
我們就可以使用prepareStatement定義一個能找到所有未付款訂單的查詢
在此還可為其它方法定義其它查詢
OrderServerImpl作為數據庫在同一個系統上運行
而且還可能是在同一個進程中(下面將討論shutDown)
當getUnpaid方法在RMI服務器對象OrderServerImpl上被調用後
就會執行預先編譯的查詢
並返回包含所有匹配元素的JDBC ResultSet對象
隨後
我們為結果集中的每個項目創建新的Order對象
並將其添加到Vector對象中( Java 的動態數組)
在結束讀取結果後
我們將這個向量返回給客戶機
後者可將結果顯示給用戶
或者其他相關的人
JNI 本機方法 RMI服務器和客戶機可利用本機方法與現有的和原有的系統連接
您可使用本機方法實現不能直接訪問數據庫的遠程方法
或者通過采用現有代碼更簡單地實現
您可使用本機接口JNI編寫C和C++程序
以實現?Java方法並 Java對象上調用該方法
用本機方法實現shutDown的程序如下
JNIEXPORT void JNICALL
Java_OrderServerImpl_shutDown(JNIEnv *env
jobject this)
{
jclass cls;
jfieldID fid;
DataSet *ds;
cls = (*env)
>GetObjectClass(env
this);
fid = (*env)
>GetFieldID(env
cls
dataSet
J
);
ds = (DataSet *) (*env)
>GetObjectField(env
this
fid);
/* With a DataSet pointer we can use the original API */
DSshutDown(ds);
}
這是假定了現有服務器通過其API定義的DataSet類型得到了引用
指向服務器DataSet的指針存儲在dataSet域中
當客戶機調用shutDown時
服務器的shutDown方法就會被調用
因為在服務器實現中聲明了要用本機方法來實現shutDown 方法
所以
RMI將直接調用這個本機方法
這個本機方法找到對象的dataSet域
得到其值
並用它調用現有API 的函數DSshutDown
Sun公司目前正與ILOG公司合作
開發一種稱作TwinPeaks 的產品
TwinPeaks將能夠兼容目前的C和C++ API
並生成 Java類
該Java類包含了到Java類中API的調用
這樣
您就能從Java調用現有的任何API
TwinPeaks面市後
將有可能完全使用Java (而非JNI調用)編寫諸如shutDown這樣的方法
體系結構 RMI系統可為分布式面向對象計算提供簡單而又直接的基礎
其體系結構可允許對服務器和引用類型進行擴展
從而使RMI能以連續的方式添加功能
當服務程序被輸出後
其引用類型就被定義
在上面的例子中
我們將服務器作為UnicastRemoteObject服務器輸出
即點到點非復制服務器
對這些對象的引用對於這類服務器非常合適
不同類型的服務器有不同的引用句法
例如
MulticastRemoteObject就有允許復制服務的引用句法
當客戶機收到向服務器的引用後
RMI就會下載一個可將該引用上的調用轉換為面向服務器的遠程調用的存根
如圖
所示
存根使用對象序列化法將參數編組到方法中
並通過網絡將經過編組的調用送到服務器
在服務器端
RMI系統接收調用
並連接到一個框架上
而框架則負責解除參數編組並在服務器上調用該方法的實現
當服務器的執行完成後
無論返回一個值或拋出一個例外
框架通過對結果進行編組
並向客戶機的存根發送一個應答
存根解除應答編組
並根據需要返回一個值或拋出一個例外
存根和框架是用服務器的實現生成的
通常使用的是程序rmic
存根使用引用與框架進行會話
這種體系結構使引用能夠定義通信的屬性
用於 UnicastRemoteObject服務器的引用與在特定主機和端口上運行的單個服務器對象進行通信
憑借存根/引用的分離功能
RMI就能添加新的引用類型
處理復制服務器的引用可將服務器請求多路發送給一組正確的復制程序
匯集響應
再根據多種響應返回正確的結果
如果服務程序沒有在虛擬機上運行
則另一個引用類型可激活該程序
客戶機可透明地與所有這些引用類型共同工作
保密與安全 在執行RMI請求時
安全是絕對有保證的
RMI可在客戶機與服務器之間提供安全信道
並可將下載的執行程序放入安全的
沙箱(sandbox)
中運行
從而保護您的系統免遭不明客戶機可能的攻擊
首先
必須定義您的安全需求
這非常重要
如果您正在安全的企業網內部執行諸如ComputeServer這樣的程序
則您只需知道誰在使用計算環路即可
這樣您就能對濫用系統的人進行跟蹤
如果您需要提供商業計算服務器
則您就需要防止多種惡意的破壞
這些都會影響接口的設計
在企業內部
您可能只要求每個Task對象都配備人名和部門編號
以便跟蹤
而在商業領域中
您可能需要更高的安全性
包括數字簽名身份識別和某些能幫助您剔除會耗費超過分配於其時間的惡意任務的合同語言
在客戶機和服務器之間您可能需要有一個安全信道
RMI可使您能提供可創建包括加密插口(socket)在內的您所需要的任何類型插口的插口工廠
從JDK
開始
您將能夠指定服務器插口所提供的服務的要求(通過給出對這些要求的描述)
這種新技術可在小應用程序上采用
而多數浏覽器都拒絕承諾設置插口工廠
插口要求可包括加密和其它要求
下載的類也存在安全問題
Java通過SecurityManager對象處理安全問題
而該對象可傳遞所有與安全有關操作的判斷
如打開文件和網絡連接等
RMI通過要求您在輸出任何服務對象或在服務器上調用任何方法之前安裝安全管理器
以使用這個標准的Java機制
RMI提供與小應用程序(無文件存取
只是連接到發出主機等)限制相同的 RMISecurityManager類型
這樣可防止下載的執行程序從計算機上讀取或寫入數據
或與防火牆後面的其它系統連接
您也可編寫和安裝自己的安全管理程序對象
以執行不同的安全限制
防火牆 RMI為防火牆後面的客戶機提供了與遠程服務器進行通信的方法
這樣可使您使用RMI在因特網上部署客戶程序
如在用於萬維網上的小應用程序中
穿越客戶機的防火牆會使通信速度降低
所以RMI成功地采用速度最快的技術連接客戶機與服務器
當客戶機首次依次嘗試下列三種可能的方法
試圖與服務器建立通信時
該技術即被UnicastRemoteObject的引用所發現
用插口(socket)直接與服務器的端口通信
如果失敗
則建立連接到服務器主機和端口上的URL
並在該URL上使用HTTP POST請求
將信息作為POST的主體發送給框架
如果成功
則post的結果就是框架對存根的響應
如果又失敗
則用端口
(標准HTTP端口)建立連接到服務器主機的URL
並使用能夠將?MI請求發送給服務器的 CGI程序
這三種技術哪一種首先成功
將來就會首先被用來與服務器進行通信
如果這些技術都不成功
則遠程方法調用失敗
這種三步策略使客戶機能夠以盡可能高的效率實現通信
並大多使用直接插口連接
在沒有安裝
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26656.html