演练 Java RMI
—— 小湖java笔记之(七)
Java RMI(Remote Method Invocation, RMI)为采用Java对象的分布式计算提供了简单而直接的途径。是纯java实现的应用通信机制。当然相比CORBA,RMI功能较弱且只能用于Java系统。假期回家期间,通过设计一个实例进行实战演练,终于对使用RMI的过程有了具体的认识。现将步骤和实例相应代码整理如下: 1.定义远程接口中的参数和返回值类型。必须保证其可以被序列化。这点往往被很多人忽视。 RMI规范其中很重要一点就是要求远程接口中的参数(返回值)应实现序列化。因为需要将客户端的对象(参数)转化成byte stream,传输到服务端后还原成服务端的对象进行调用。或者是需要将服务端的对象(返回值)转化成byte stream,传输到客户端还原成客户端的对象进行调用。当然,基本数据类型以及String,数组等都已经是可序列化的。在演习的例子中,参数等都比较简单,没有涉及到这个步骤。(顺便查阅了不少关于序列化的文章,相关内容将另成一篇。) 2.定义一个远程接口,该接口继承java.rmi.Remote,同时定义了所有将被远程调用的方法。这些方法必须抛出 RemoteException 异常。
WeatherForecastRemote.java:
package com.xiaohu_studio.weatherforecast;
import java.rmi.*;
public interface WeatherForecastRemote extends Remote {
String WFToday() throws RemoteException; String WFTomorrow() throws RemoteException; }
3.定义一个继承于java.rmi.UnicastRemoteObject且实现上述接口的类。将要被远程调用的对象就是这个类的对象。要注意的是,必须要有最少一个显式的构造函数。构造函数必须抛出RemoteException异常。
WeatherForecast.java:
package com.xiaohu_studio.weatherforecast;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject; public class WeatherForecast extends UnicastRemoteObject implements
WeatherForecastRemote { static String[] description={"Sunny","Cloudy","Rainy","Windy"}; public WeatherForecast() throws RemoteException {}
public String WFToday() throws RemoteException {
return description[(int)(Math.random()*4)]; } public String WFTomorrow() throws RemoteException {
return description[(int)(Math.random()*4)]; } }
4.编写服务端代码,创建和安装一个安全性管道,并注册远程对象。发现可以忽略安装安全性管道。如果安装的话,必须创建一个安全策略文件,否则会出现AccessControlException。客户端也一样。
WeatherForecastServer.java
package com.xiaohu_studio.weatherforecast;
import java.rmi.*;
import java.rmi.registry.*; //import java.rmi.server.*; //import java.net.*; public class WeatherForecastServer {
public static void main(String[] args) {
if (System.getSecurityManager() == null) { System.out.println("Set Security Manager."); System.setSecurityManager(new RMISecurityManager()); } try { WeatherForecast wf=new WeatherForecast(); LocateRegistry.createRegistry(8898); // 注册端口 Naming.bind("rmi://127.0.0.1:8898/wf",wf); } catch (Exception e) { System.out.print("Error---- "+e.toString()); e.printStackTrace(); } } } 安全策略文件policy.txt: grant {
permission java.security.AllPermission; //Allow everything for now }; (步骤3和4可以合并成一个类。)
5.编写客户端代码,创建和安装一个安全性管道,查找远程对象,并调用远程方法
WeatherForecastClient.java:
package com.xiaohu_studio.weatherforecast;
import java.rmi.*;
public class WeatherForecastClient { public static void main(String[] args) { if (System.getSecurityManager() == null) { System.out.println("Set Security Manager."); System.setSecurityManager(new RMISecurityManager()); } try { WeatherForecastRemote ff; //System.out.println("Lookup the Remote object."); ff=(WeatherForecastRemote)Naming.lookup("rmi://127.0.0.1:8898/wf"); //注意是WeatherForecastRemote,而不是WeatherForecast,否则抛出ClassCastException. System.out.print("Today‘s weahter: "); System.out .println(ff.WFToday()); System.out.print("Tomorrow‘s weather: "); System.out .println(ff.WFTomorrow()); } catch (Exception e){ System.out.println("Error:"+e.toString()); } }
}
6.生成stub和skeltion ,并将stub打包到客户端jar中,将skeltion打包到服务端jar中。
在演习的例子的时候,发现用直接mic命令(不带参数)只生成_Stub.class,将该_Stub.class同时打包到客户端和服务端即可。
rmic com.xiaohu_studio.weatherforecast.WeatherForecast
(如果需要生成_Slel.calss,则需用rmic -vcompat 命令)
7.用命令 rmiregistry 命令来启动RMI注册服务。
在命令行输入命令 :
start rmiregistry 8898 如果在服务端代码中包含了启动RMI注册服务的代码(LocateRegistry.createRegistry(8808);),则可以省略该步骤。 8.运行服务端及客户端代码。
服务端文件:(目录:d:\server\com\xiaohu_studio\weatherforecast) policy.txt WeatherForecastRemote.class WeatherForecast.class WeatherForecastServer.class WeatherForecast_Stub.class 服务端运行命令:(目录:d:\client\com\xiaohu_studio\weatherforecast)
java -Djava.security.policy=com\xiaohu_studio\weatherforecast\policy.txt com.xiaohu_studio.weatherforecast.WeatherForecastServer 客户端文件: policy.txt WeatherForecastRemote.class WeatherForecast_Stub.class 客户端运行命令:
java -Djava.security.policy=com\xiaohu_studio\weatherforecast\policy.txt com.xiaohu_studio.weatherforecast.WeatherForecastClient |
|
来自: ShangShujie > 《java》