Java RMI

1、RMI概述
RMI(Remote Method Invocation)
RMI是分布式对象软件包,方便了JAVA应用程序在多台计算机之间的通信。
必须在jdk1.1以上
RMI用到的类:
java.rmi.Remote
所有可以被远程调用的对象都必须实现该接口
java.rmi.server.UnicastRemoteObject
所有可以被远程调用的对象都必须扩展该类
优点:
方便了JAVA应用程序在多台计算机之间的通信。
只要按照RMI规则设计程序,可以不必再过问在RMI之下的网络细节了,如:TCP和Socket等等。
任意两台计算机之间的通讯完全由RMI负责。调用远程计算机上的对象就像本地对象一样方便。
创建远程方法调用的5个步骤:
1、定义一个继承了远程接口的接口,该接口中的每一个方法必须声明它将产生一个RemoteException异常。
2、定义一个实现该接口的类。
3、使用RMIC程序生成远程实现所需的残根和框架。存根(stub)和框架(skeleton)
4、创建一个客户程序和服务器进行RMI调用。
5、启动Registry并运行自己的远程服务器和客户程序。
对应上面的步骤分析:
1.
所有的RMI操作都应放到try-catch块中:
由于任何远程方法调用实际上要进行许多低级网络操作,因此网络错误可能在调用过程中随时发生.
2.
实现该接口的类(服务端类):必须继承UnicastRemoteObject类。
扩展java.rmi.server.UnicastRemoteObject
UnicastRemoteObject顾名思义,是让客户机与服务器对象实例建立一对一的连接。
3.
在RMI中,客户机上生成的调动调用参数和反调动返回值的代码称为残根。有的书上称这部分代码为“主干”。
服务器上生成的反调动调用参数和进行实际方法调用调动返回值的代码称为框架。
生成残根和框架的工具
Rmic命令行工具(RMI Compiler)
格式:
Rmic classname
4.
第五步、用RmiRegistry找到远程对象
这是一个使用工具,维护文本名和远程对象之间的映射,可以进行远程访问。

如下面的实例:
若手动运行的话,要用:
rmic RemotePrinterImpl  生成Stub 和 Skeleton,它们实际上是远程调用的底层的实现。
start rmiregistry       启动rmi的注册程序,使文本名和远程对象之间的映射,实现远程访问. 
java RemotePrinterImpl  启动服务器
java PrintClient        启动客户端
===========================在eclipse中创建RMI实例=================================
(一)创建接口端:
1.
在eclpse中创建一个java project-->project's layout选择分开放置.
2.
在project中,添加一个package-->选择,新建一个 Remote Interface(不是简单的interface),默认完成.
3.
在接口在写入各抽象方法,都要用throws RemoteException.
如下:
public interface RemotePrinter extends Remote { 
 public int submitJob(String text) throws RemoteException; 
 public boolean isComplete(int jobID) throws RemoteException; 
 public String getPrinterStatus() throws RemoteException;  
}
(二)创建服务端:
1.
在eclpse中创建一个java project-->project's layout选择分开放置-->切换到project分页,添加接口的project包-->默认完成.
2.
在project中,添加一个package-->新建一个JAVA类-->其父类要选择:UnicastRemoteObject-->其实现的接口,要添加刚创建的接口-->默认完成.
3.
添加自己的构造方法带throws RemoteException.
4.
对接口的方法,进行实现.
5.
在main方法中:
用try..catche,防止有异常.
进行注册: Registry r=LocateRegistry.getRegistry();
进行绑定:r.bind("printer", new RemotePrinterImpl());
输入成功提示:System.out.println("printer server is ready");
6.
生成子根:
点击 server的整个project package,右键-->RMI-->Enabel subs ... -->系统会自动生成子根.
(三)创建客户端:
1.
在eclpse中创建一个java project-->project's layout选择分开放置-->切换到project分页,添加接口的project包-->默认完成.
2.
在project中,添加一个package-->新建一个JAVA类,默认完成.
3.
在main方法中:
用try..catche,防止有异常.
设置安全管理;
连接服务端,利用接口实例化服务端对象;
用新建实例调用各方法进行运用.
如下:
System.setSecurityManager(new RMISecurityManager());
RemotePrinter jprinter=(RemotePrinter)Naming.lookup("rmi://localhost/printer");
int jobID=jprinter.submitJob("hello word");
System.out.println("submitted job's ID: "+jobID);
System.out.println("is complete ? "+jprinter.isComplete(jobID));
System.out.println("printer status: "+jprinter.getPrinterStatus());
(四)
如何运行:
1.
在RMI工具键,下拉选择start locale Registry; -->弹出提示,选择NO.
2.
右键点击SERVER类,用RMI application进行运行--->第一次运行时,会弹出配置对话框-->切换到RMI VM Properties -->选择java.rmi.server.codebase-->add-->点击compute from classpath-->完成即可.
3.
右键点击CLIENT类,用RMI application进行运行--->第一次运行时,会弹出配置对话框-->切换到RMI VM Properties -->选择java.security.policy-->add-->create-->选择CLIENT的project包-->完成即可.
--->上面记录具体是否有错,明晚再试.

===============================将RMI实例打包运行==================================
0.
先要运行:
C:\Program Files\Java\jre1.5.0_09\bin>start rmiregistry
==>
如何避免要进行此步后,才能进行启动SERVER.
原因:
因为在server端的代码中用: Registry r=LocateRegistry.getRegistry();
而要让程序自动启动RMI注册程序: Registry r=LocateRegistry.createRegistry(端口号);
而在客户端: -->也应该添加相应的端口
RemotePrinter jprinter=(RemotePrinter)Naming.lookup("rmi://localhost:8888/printer");
1.
对于SERVER端:
1.1
打包时,也要一起打上接口的包.不能单独只打SERVER包.
1.2
写运行bat时,只须:
java -Xmx350M -jar  -Djava.rmi.server.codebase=file:///D:/printer/server/server.jar server.jar
分析:
-Djava.security.policy不是必要的, -->服务器不用去连接其它人,是其它人来连接它的.所以不用安全验证.
而-Djava.rmi.server.codebase则是必要的-->否则会出现找不到存根的错.-->codebase,是给客户端连接用的.所以一定要.

2.
对于CLIENT端: -->可放在任何放不用改路径.
第一种设置方法:
1)
打包时,也要一起打上接口的包.不能单独只打client包.
2)
写运行bat时:
java -Xmx350M -jar -Djava.security.policy=./etc/security.policy client.jar
分析:
-Djava.security.policy=./etc/security.policy:用来通过RMI的安全验证.否则不能进入.

双保险的方式是:
用上面的方式,同时用以下的方式(设置MANIFEST.MF以及添加相应的目录和jar包),两者同时存在.
以下方式,可以不用.
第二种设置方法:  -->须加设置且加lib文件夹,但
2.1
打包时,不用也一起打上接口的包.
1.2
写运行bat时,只须:
java -Xmx350M -jar -Djava.security.policy=./etc/security.policy client.jar
分析:
-Djava.security.policy是必要的,
而-Djava.rmi.server.codebase则不是必要的.
1.3
同时要修改MANIFEST.MF:
Manifest-Version: 1.0
Class-Path: lib/interface.jar                 -->添加项,且在目录下建lib目录,放接口的包
Main-Class: demo.rmi.print.client.PrintClient

===============================另一实例===============================
-------------RMIInterface.java:
public interface RMIInterface extends Remote {
 public int submitJob(String text) throws RemoteException;
 public boolean isComplete(int jobID) throws RemoteException;
 public String getPrinterStatus() throws RemoteException; 
}
-----------RMIServer.java
public class RMIServer extends UnicastRemoteObject implements RMIInterface {
 private static Logger logger=Logger.getLogger(RMIServer.class.getName());
 
 public RMIServer() throws RemoteException
 {
  try
  {    
RMIConfig rmiconfig=new RMIConfig("etc/RMIconfig.cfg");
Registry r=LocateRegistry.createRegistry(Integer.parseInt(rmiconfig.getPort()));
String RMIurl="rmi://"+rmiconfig.getHostName()+":"+rmiconfig.getPort()+"/"+rmiconfig.getServiceName();
   logger.info("rebind name :"+RMIurl);   
   Naming.rebind(RMIurl,this);
  }
  catch(Exception e)
  {
   e.printStackTrace();
  }
 }
 public String getPrinterStatus() throws RemoteException {
  System.out.println("requested the printer status");
  return "OK";
 }
 public boolean isComplete(int jobID) throws RemoteException {
  System.out.println("requested the job status");
  return true;
 }
 public int submitJob(String text) throws RemoteException {
  System.out.println("submitted job "+text);
  return 0;
 }
 public static void main(String[] args) {
  try
  {
   File f=new File("etc/log4j.properties");
   if(!f.exists())
   {
    logger.fatal("the log4j.properties is not exist");
    System.exit(0);
   }
   PropertyConfigurator.configure("etc/log4j.properties");
   RMIServer server=new RMIServer();
  }
  catch(Exception e)
  {
   e.printStackTrace();
  }
 }
}
---------------RMIClient.java
public class RMIClient {
 private static Logger logger=Logger.getLogger(RMIClient.class.getName());
 public RMIClient()
 {
  try
  {
   logger.info("Start RMI Client ......");
   RMIConfig rmiconfig=new RMIConfig("etc/RMIconfig.cfg");
   
   System.setSecurityManager(new RMISecurityManager());
   String rmiUrl="rmi://"+rmiconfig.getHostName()+":"+rmiconfig.getPort()+"/"+rmiconfig.getServiceName();
   RMIInterface jprinter=(RMIInterface)Naming.lookup(rmiUrl);
   int jobID=jprinter.submitJob("hello word");
   System.out.println("submitted job's ID: "+jobID);
   System.out.println("is complete ? "+jprinter.isComplete(jobID));
   System.out.println("printer status: "+jprinter.getPrinterStatus());
   
  }
  catch(Exception e)  
  {
   
  }
 }
 public static void main(String[] args) {
  
  try
  {
   File file=new File("etc/log4j.properties");
   if(!file.exists())
   {
    logger.fatal("the log4j.properties is not exist");
    System.exit(0);
   }
   PropertyConfigurator.configure("etc/log4j.properties");
   
   RMIClient client=new RMIClient();
  }
  catch(Exception e)
  {
   e.printStackTrace();
  }
 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值