Java2 RMI 入門 作者:jdeveloper
RMI從Java1.1開始,RMI使得運行於不同JVM(包括不同主機)上的Java應用程式可以彼此通話。
即:一個JVM中的Java應用程式可以調用另一JVM上的對象(遠程對象)所定義的方法。
Java RMI有著重要的意義。RMI在Java網路編程和進階編程中都有重要的應用,如EJB, Jini等。
Java2對RMI做了很多增強和改進,如安全性,動態代碼下載等。
本文給出了一個最簡單的例子,以說明其中的一些基本原理。本文的特點是注重了實際開發和真正的運行
環境相結合,類比了RMI真正的開發和運行過程。
1. 實現遠程介面,產生遠程對象,存根(Stub)和架構(Skeleton)
實現遠程介面,遠程介面告訴JVM:實現了該介面的對象可以遠程調用及有哪些方法可以調用。
本例子中定義了sayHello()。由於遠程調用會涉及到網路通訊,因此這些方法都要拋出RemoteException.
遠程介面和遠程對象可以由A開發,並把遠程介面(Hello)d打包分給Client端開發人員B。
建立f:/server目錄,把Hello.java和HelloImpl.java拷貝到該目錄中。
// Hello.java
package jdeveloper.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
產生遠程對象.
// HelloImpl.java
package jdeveloper.rmi;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
public class HelloImpl extends UnicastRemoteObject
implements Hello {
public HelloImpl() throws RemoteException {
super();
}
public String sayHello() {
return "Hello World!";
}
public static void main(String args[]) {
// Create and install a security manager
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
Hello obj = new HelloImpl();
// Bind this object instance to the name "HelloServer"
Naming.rebind("HelloServer", obj);
System.out.println("HelloServer bound in registry");
} catch (Exception e) {
System.out.println("HelloImpl err: " + e.getMessage());
e.printStackTrace();
}
}
}
存根(Stub)和架構(Skeleton)
f:
cd /server
javac -d . Hello.java
javac -d . HelloImpl.java
rmic -d . jdeveloper.rmi.HelloImpl
jar cvf hello.jar jdeveloper/rmi/Hello.class 把hello.jar分發給Client端的開發人員B。
存根(Stub)的存放!
存根(Stub)是動態下載的。Client通過存根(Stub)和遠程對象的架構(Skeleton)通訊,對Client來
講就象操作本機物件一樣。在大多數情況下,可下載的代碼放到http伺服器的某個目錄中。本例子放到http://hjc/rmi下。
hjc:機器名,rmi:http的一個目錄。如果只是單機測試則可以放到某個目錄下 如f:/serverclasses.
本文將對以上兩種方法都給出啟動並執行步驟(policy檔案和bat檔案)。
2. 實現Client端程式
// HelloClient.java
package jdeveloper.rmi;
import java.rmi.RMISecurityManager;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.NotBoundException;
public class HelloClient {
public static void main(String args[]) throws Exception{
System.setSecurityManager(new RMISecurityManager());
Hello RemoteObj = (Hello)Naming.lookup("//"+ args[0] +"/HelloServer");
System.out.println(RemoteObj.sayHello());
}
}
建立f:/client目錄,把HelloClient.java拷貝到該目錄中。
建立f:/clientclasses目錄,把hello.jar拷貝到該目錄中。
f:
cd /client
javac -classpath %CLASSPATH%;f:/clientclasses/hello.jar -d . HelloClient.java
3. 運行程式
啟動DOS視窗
set classpath=
start rmiregistry
A.以單機方式運行
建立f:/serverclasses/jdeveloper/rmi目錄
f:
cd f:/serverclasses
copy f:/server/hello.jar .
copy f:/server/jdeveloper/rmi/HelloImpl_Stub.class f:/serverclasses/jdeveloper/rmi/
jar xvf hello.jar
啟動新的DOS視窗
把 starthelloserver.bat 和 rmiserver.policy 放到f:/server/
運行 starthelloserver
starthelloserver.bat
SET CP=f:/server;f:/serverclasses/hello.jar
echo using classpath: %CP%
java -classpath %CP% -Djava.rmi.server.codebase=file:/f:/serverclasses/
-Djava.rmi.server.hostname=hjc -Djava.security.policy=rmiserver.policy jdeveloper.rmi.HelloImpl
rmiserver.policy
grant {
permission java.net.SocketPermission "*:1024-65535",
"connect";
};
啟動新的DOS視窗
把 starthelloclient.bat 和 rmiclient.policy 放到f:/client/
運行 starthelloclient
starthelloclient.bat
@echo off
set CP=f:/client;f:/clientclasses/hello.jar
echo using classpath %CP%
@echo on
java -classpath %CP% -Djava.rmi.server.codebase=file:/f:/serverclasses/
-Djava.security.policy=rmiclient.policy jdeveloper.rmi.HelloClient %1
rmiclient.policy
grant {
permission java.net.SocketPermission "*:1024-65535",
"connect";
permission java.io.FilePermission
"f://serverclasses//-", "read";
};
B.以網路方式運行
建立 apache_path/htdocs/rmi/jdeveloper/rmi目錄
cd apache_path/htdocs/rmi
copy f:/server/hello.jar .
copy f:/server/jdeveloper/rmi/HelloImpl_Stub.class apache_path/htdocs/rmi/jdeveloper/rmi
jar xvf hello.jar
把 starthellohttpserver.bat 和 rmihttpserver.policy 放到f:/server/
啟動新的DOS視窗
運行 starthellohttpserver
starthellohttpserver.bat
SET CP=f:/server;f:/serverclasses/hello.jar
echo using classpath: %CP%
java -classpath %CP% -Djava.rmi.server.codebase=http://hjc/rmi/
-Djava.security.policy=rmihttpserver.policy jdeveloper.rmi.HelloImpl
rmihttpserver.policy
grant {
permission java.net.SocketPermission "*:1099", "accept, connect, listen, resolve";
permission java.net.SocketPermission "*:80", "accept, connect, listen, resolve";
};
啟動新的DOS視窗
把 starthellohttpclient.bat 和 rmihttpclient.policy 放到f:/client/
運行 starthellohttpclient
starthellohttpclient.bat
@echo off
set CP=f:/client;f:/clientclasses/hello.jar
echo using classpath %CP%
@echo on
java -classpath %CP% -Djava.rmi.server.codebase=http://hjc/rmi/
-Djava.security.policy=rmihttpclient.policy jdeveloper.rmi.HelloClient %1
rmihttpclient.policy
grant {
permission java.net.SocketPermission "*:80", "connect";
permission java.net.SocketPermission "*:1024-65535", "connect";
};