RMI介绍

RMI是Remote Method Invocation(远程方法调用)的 所写。它允许一个Java程序调用网络中另一台计算机上的Java方法,就如调用本机的方法一样。实现RMI调用的程序和被调用的方法,都必须是Java代码,即客户端和服务器端都必须通过纯Java实现。

RMI是基于Java的分布式编程模型,使用RMI进行远程方法调用时,无须考虑方法底层的网络传输细节。下面使用RMI的示例程序:

先编写RMI服务器端,RMI需要通过远程接口“暴露”服务。也就是说,所有想被客户机调用的方法都必须在Remote接口里声明,否则无法完成调用。远程接口如下:

远程接口必须集成java.rmi.Remote接口

public interface Server extends Remote

{

//所有在Remote接口里声明的方法都必须抛出RemoteException异常

String helloWorld(String name) throws RemoteException;

Person getPerson(String name,int age)throws RemoteException;

}

远程接口必须继承java.rmi.Remote接口。远程接口里声明的方法会通过网络传输,而网络是不可靠的,因此,所有的远程方法都必须抛出RemoteException。RMI服务是典型的面向接口编程,只有在远程接口里定义的方法才会作为远程服务。

下面是远程服务提供类,远程服务提供类必须实现远程接口,并继承java.rmi.server.UnicastRemoteObject对象,继承该类能“暴露”远程服务。

//远程服务类,远程服务类必须继承UnicastRemoteObject,并实现Remote接口

public class ServerImpl extends UnicastRemoteObject implements Server

{

//远程服务类必须拥有构造器,且构造器必须抛出RemoteException异常

public ServerImpl()throws RemoteException

{

}

//实现Remote接口必须实现的方法

public String helloWorld(String name)throws RemoteException

{

return name + ", 您好!";

}

//实现Remote接口必须实现的方法

public Person getPerson(String name,int age)throws RemoteException

{

return new Person(name,age);

}

//下面是服务类的本地方法,不会“暴露”为远程服务。

public void info()

{

System.out.println(“我是本地方法”);

}

//下面提供程序入口,将远程类实例绑定为本机的服务。

public static void main(String[] args)throws Exception

{

//创建远程服务类实例

Server imp = new ServerImpl();

//注册远程服务的端口

LocateRegistry.createRegistry(1099);

//将远程服务实例绑定为远程服务。

Naming.rebind("rmi://:1099/fdf", imp);

}

}

远程服务类必须有构造器,即使找个构造器什么都不做。而且,构造器必须抛出RemoteException异常。将两个编辑好的源文件存盘,然后编译。对于使用RMI,仅仅编译还不够,还必须使用rmic命令编译服务类,编译服务类是为了生成stub和skeleton——查看存放class文件的地方,多了如下两个class文件:

q ServerImpl_Stub.class

q ServerImpl_Skel.class

这两个类就是服务类生成的stub和skeleton。客户端程序面向接口编程,客户端部分需要Server接口的class文件,还需要stub文件。客户端的源代码如下:

public class RMIClient

{

//主方法,程序入口

public static void main(String[] args)throws Exception

{

//通过JNDI查找远程服务

Server ser = (Server)Naming.lookup("rmi://:1099/fdf");

//调用远程方法

System.out.println(ser.helloWorld("yeeku"));

//调用远程方法。

System.out.println(ser.getPerson("yeeku",28));

}

}

从客户端程序看,无法感受到Server的实现在远端。程序调用Server实例方法时,与平常调用方法只有非常细微的区别:调用远程方法必须抛出RemoteException。

再看远程方法的返回值,helloWorld的返回值是String,而getPerson的返回值则是Person对象。远程方法的返回值必须有一个要求:实现Serializable接口。因为远程的方法的参数、返回值都必须在网络上传输,网络只能传输字节流,因此,要求参数、返回值都可以转换成字节流——即实现序列化。主程序的如下一行代码,用于注册远程服务端口:

LocateRegistry.createRegistry(1099);

1099是RMI服务的默认端口。然后执行如下代码绑定远程服务

Naming.rebind("rmi://:1099/fdf", imp);

客户端使用JNDI查找,查找远程服务名。将远程服务对象类型转换成远程接口类型,客户端面向接口编程。RMI的具体实现,依然是依赖于底层的Socket编程。RMI依赖于TCP/IP传输协议,服务器端skeleton建立ServerSocket监听请求,而客户端建立Socket请求连接。RMI实现了网络传输的多线程、IO等底层细节。这些细节的实现就隐藏在rmic命令的执行中:使用rmic命令编译时生成的两个class文件:

q stub:该文件用于与客户端交流,建立Socket请求连接。

q skeleton:该文件用于与服务器端交流,建立ServerSocket监听请求。

RMI的原理示意如图所示。


[img]http://dl.iteye.com/upload/attachment/475603/df9beaeb-5fb6-3ee0-a716-75e1e3db0f5c.jpg[/img]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值