RMI实例祥解.docx
《RMI实例祥解.docx》由会员分享,可在线阅读,更多相关《RMI实例祥解.docx(15页珍藏版)》请在冰豆网上搜索。
RMI实例祥解
RMI简单实例
2007-01-0312:
26
分布式对象技术主要是在分布式异构环境下建立应用系统框架和对象构件。
在应用系统框架的支撑下,开发者可以将软件功能封装为更易管理和使用的对象,这些对象可以跨越不同的软、硬件平台进行互操作。
目前,分布式互操作标准主要有Microsoft的COM/DCOM标准、Sun公司的Java RMI标准和OMG组织的CORBA标准。
Java RMI简介
远程方法调用(RMI,Remote Method Invocation)是jdk1.1中引入的分布式对象软件包,它的出现大大简化了分布异构环境中Java应用之间的通信。
要使用RMI,必须构建四个主要的类:
远程对象的本地接口、远程对象实现、RMI客户机和RMI服务器。
RMI服务器生成远程对象实现的一个实例,并用一个专有的URL注册。
RMI客户机在远程RMI服务器上查找服务对象,并将它转换成本地接口类型,然后像对待一个本地对象一样使用它。
下面是一个简单的RMI实例,RMI客户机通过RMI服务器提供的方法输出一个语句。
例子虽然很简单,但掌握了Java RMI调用的基本原理和方法,在实现复杂应用时,我们需要做的也只是完善远程对象的实现类而已。
RMI实例分析
1.远程对象的本地接口声明(RMIOperate.java)
· 该类仅仅是一个接口声明,RMI客户机可以直接使用它,RMI服务器必须通过一个远程对象来实现它,并用某个专有的URL注册它的一个实例。
· 远程接口扩展 java.rmi.Remote 接口。
· 除了所有应用程序特定的例外之外,每个方法还必须在 throws 子句中声明 java.rmi.RemoteException(或 RemoteException 的父类)。
Hello.java
/* * @author javamxj (CSDN Blog) 创建日期 2004-12-27 */ import java.rmi.*; // RMI本地接口必须从Remote接口派生 public interface Hello extends Remote { // 接口中的具体方法声明,注意必须声明抛出RemoteException String sayHello(String name) throws RemoteException; }
2.远程对象实现类
这个类应实现RMI客户机调用的远程服务对象的本地接口,它必须从UnicastRemoteObject继承,构造函数应抛出RemoteException异常。
HelloImpl.java
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import java.rmi.*;
import javax.rmi.PortableRemoteObject;
public class HelloImpl extends PortableRemoteObject implements Hello {
/* 构造函数 */
public HelloImpl() throws RemoteException {
super();
}
/* 实现本地接口中声明的'sayHello()'方法 */
public String sayHello(String message) throws RemoteException {
System.out.println("我在RMI的服务器端,客户端正在调用'sayHello'方法。
");
System.out.println("Hello " + message);
return message;
}
}
3.RMI服务器类
该类创建远程对象实现类HelloImpl的一个实例,然后通过一个专有的URL来注册它。
所谓注册就是通过Java.rmi.Naming.bind()方法或Java.rmi.Naming.rebind()方法,将HelloImpl实例绑定到指定的URL上。
HelloServer.java
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import java.rmi.*;
public class HelloServer {
public static void main(String[] args) {
// 在服务器端设置安全机制
/*
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
*/
try {
System.out.println("开始 RMI Server ...");
/* 创建远程对象的实现实例 */
HelloImpl hImpl = new HelloImpl();
System.out.println("将实例注册到专有的URL ");
Naming.rebind("HelloService", hImpl);
System.out.println("等待RMI客户端调用...");
System.out.println("");
} catch (Exception e) {
System.out.println("错误:
" + e);
}
}
}
请注意有关 rebind 方法调用的下列参数:
∙第一个参数是 URL 格式的 java.lang.String,表示远程对象的位置和名字。
o需要将 myhost 的值更改为服务器名或 IP 地址。
否则,如果在 URL 中省略,则主机缺省值为当前主机,而且在 URL 中无需指定协议(例如“HelloServer”)。
o在 URL 中,可以选择提供端口号:
例如“//myhost:
1234/HelloServer”。
端口缺省值为 1099。
除非服务器在缺省 1099 端口上创建注册服务程序,否则需要指定端口号。
∙第二个参数为从中调用远程方法的对象实现引用。
∙RMI 运行时将用对远程对象 stub 程序的引用代替由 hImpl 参数指定的实际远程对象引用。
远程实现对象(如 HelloImpl 实例)将始终不离开创建它们的虚拟机。
因此,当客户机在服务器的远程对象注册服务程序中执行查找时,将返回包含该实现的 stub 程序的对象。
4.RMI客户机类
· RMI客户使用java.rmi.Naming.lookup()方法,在指定的远程主机上查找RMI服务对象,若找到就把它转换成本地接口RMIOperate类型。
它与CORBA不同之处在于RMI客户机必须知道提供RMI服务主机的URL,这个URL可以通过rmi:
//host/path或rmi:
//host:
port/path来指定,如果省略端口号,就默认使用1099。
· Java.rmi.Naming.lookup()方法可能产生三个异常:
Java.rmi.RemoteException、Java.rmi.NotBoundException、. MalformedURLException,三个异常都需要捕获。
HelloClient.java
/*
* @author javamxj (CSDN Blog) 创建日期 2004-12-27
*/
import java.rmi.*;
public class HelloClient {
public static void main(String[] args) {
// 在服务器端设置安全机制
/*
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
*/
/* 默认为本地主机和默认端口 */
String host = "localhost:
1099";
/* 带输入参数时,将host设置为指定主机 */
if (args.length > 0)
host = args[0];
try {
/* 根据指定的URL定位远程实现对象 */
/* “h”是一个标识符,我们将用它指向实现“Hello”接口的远程对象 */
Hello h = (Hello) Naming.lookup("rmi:
//" + host + "/HelloService");
System.out.println("实现“Hello”接口的远程对象:
" + h);
System.out.println("我在客户端,开始调用RMI服务器端的'sayHello'方法");
System.out.println("欢迎, " + h.sayHello("javamxj blog"));
} catch (Exception ex) {
System.out.println("错误 " + ex);
}
}
}
5. 编译代码与运行系统:
在MS-DOS环境下,创建一个D:
\RMISample目录,把上面4个文件复制到这个目录下,然后在此目录下新建两个文件夹:
client和server(把它们分别看作是客户端与服务端)。
(1).编译所有的源代码
D:
\RMISample> javac *.java
(2).生成客户端存根和服务器框架
D:
\RMISample> rmic HelloImpl
这将生成HelloImpl_Stub.class和HelloImpl_Skel.class。
( 注:
如果需要查看这两个类的源代码,可以使用“ rmic -keep HelloImpl”语句
如果是JDK1.4以上的版本,则不会生成_Skel文件,用_Stub文件代之即可
如果执行rmic提示找不到文件,则要在环境变量中的classPath下追加HelloImpl.class所在的目录)
(3).把Hello.class、HelloClient.class、HelloImpl_Stub.class复制到client目录;
把Hello.class、HelloServer.class、HelloImpl_Skel.class、HelloImpl_Stub.class 复制到server目录。
(4).启动RMI注册
D:
\RMISample\server>rmiregistry
(注:
我是在命令控制台下运行这个系统的,必须开启三个控制台窗口,一个运行RMIRegistry,一个运行服务器,还有一个运行客户端。
)
(5).运行和调用
● 在服务器上执行HelloServer
D:
\RMISample\server>java HelloServer
● 在本地客户机上运行HelloClient
D:
\RMISample\client>java HelloClient
● 在远程客户机上运行HelloClient(须指明RMI服务器主机名或IP地址)
java HelloClient 222.222.34.34
运行rmiregistry和server后的结果:
再运行Client后的结果:
还有一点要注意,在上面的例子中我注释了安全管理的代码,如果把注释去掉,那么需要建立一个安全策略文件,比如其文件名为 policy.txt,内容如下:
grant {
permission java.security.AllPermission "", "";
};
这是一条简单的安全策略,它允许任何人做任何事,对于你的更加关键性的应用,你必须指定更加详细安全策略。
把这个文件复制到Client和Server目录,然后如下运行:
D:
\RMISample\server>java -Djava.security.policy=policy.txt HelloServer
D:
\RMISample\client>java -Djava.security.policy=policy.txt HelloClient
类别:
Java|
|添加到搜藏|分享到i贴吧|浏览(2595)|评论 (5)
上一篇:
SOAP学习 下一篇:
SQL语句
最近读者:
languanfu111
求剑传说
bd_hare
ahunspun12
Fa_dying
鹬ヤ蚌蝦
jld198502
郝文龙北纬
网友评论:
1
crazyguo007
2007-08-2119:
42|回复
写得非常不错,一看就明白怎么用rmi编程了
2
网友:
sezelee
2007-08-2216:
02|回复
RMI运行时将用对远程对象stub程序的引用代替由hImpl参数指定的实际远程对象引用。
谁看的懂!
说不明白,用几句说不行吗?
3
wuyunsheng502
2007-08-3111:
04|回复
好文章
4
网友:
heshen
2007-11-1711:
29|回复
我按你的步骤,在第
(2)步中只生成了HelloImpl_Stub.class,没生成HelloImpl_Skel.class啊,,这是为什么咯?
?
请帮忙指点一下!
!
!
!
5
130509
2009-01-0809:
42|回复
不错,容易学习。
感谢分享
RMI的简易使用方法
2010-05-2814:
3732人阅读评论(0)收藏举报
一般来说,使用RMI的时候,客户端都要从服务端下载一个_stub存根类,这样做很不方便。
一个简单的RMI调用的方法如下:
在服务端定义一个继承Remote接口的接口Server,在这个接口里面定义我们要在客户端进行访问的方法。
然后编写远程对象类实现这个Server接口。
服务端示例代码如下:
定义接口
[java]viewplaincopyprint?
1.package rmi.server;
2.import java.rmi.Remote;
3.import java.rmi.RemoteException;
4.//定义接口
5.public interface Server extends Remote{
6. public void hello() throws RemoteException;
7.}
定义远程对象
[java]viewplaincopyprint?
1.package rmi.server;
2.import .MalformedURLException;
3.import java.rmi.AlreadyBoundException;
4.import java.rmi.Naming;
5.import java.rmi.RemoteException;
6.import java.rmi.registry.LocateRegistry;
7.import java.rmi.server.UnicastRemoteObject;
8.import java.util.logging.Level;
9.import java.util.logging.Logger;
10./**
11. *
12. * @author zhangrenbin
13. */
14.public class ServerImpl extends UnicastRemoteObject implements Server{
15. public void hello() {
16. System.out.print("who are you");
17. }
18. public ServerImpl() throws RemoteException{
19.
20. }
21. public static void main(String[] args) throws AlreadyBoundException {
22. ServerImpl server;
23. try {
24. server = new ServerImpl();
25. //设置安全沙箱
26. /*
27. System.setProperty("java.security.policy", "server.policy");
28. if (System.getSecurityManager() == null) {
29. System.setSecurityManager(new SecurityManager());
30. }
31. * */
32. LocateRegistry.createRegistry(5201); //在本地5201端口开辟一个注册表
33. try {
34. Naming.bind("rmi:
//localhost:
5201/sdf", server); //在命名目录绑定远程对象
35. } catch (MalformedURLException ex) {
36. Logger.getLogger(ServerImpl.class.getName()).log(Level.SEVERE, null, ex);
37. }
38. } catch (RemoteException ex) {
39. Logger.getLogger(ServerImpl.class.getName()).log(Level.SEVERE, null, ex);
40. }
41. }
42.}
在客户端同样定义一个同样的Server接口(包名也必须一致),从而我们就可以直接把从注册表中读出来的远程对象转换成Server类型的。
这样我们就不需要存根对象。
当然这样做存在局限性(客户端必须定义与服务端同样的接口),但是只要约定好了,会简化RMI的配置和使用。
客户端示例代码如下:
定义接口:
[java]viewplaincopyprint?
1.package rmi.server;
2.import java.rmi.Remote;
3.import java.rmi.RemoteException;
4.//定义接口
5.public interface Server extends Remote{
6. public void hello() throws RemoteException;
7.}
读取远程对象:
[c-sharp]viewplaincopyprint?
1.package rmi.client;
2.import .MalformedURLException;
3.import java.rmi.Naming;
4.import java.rmi.NotBoundException;
5.import java.rmi.RemoteException;
6.import java.util.logging.Level;
7.import java.util.logging.Logger;
8.import rmi.server.Server;
9./**
10. *
11. * @author zhangrenbin
12. */
13.public class Client {
14. public static void main(String[] a) {
15. try {
16. Server server = (Server) Naming.lookup("rmi:
//localhost:
5201/sdf");
17. server.hello();
18. } catch (NotBoundException ex) {
19. Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
20. } catch (MalformedURLE