RMI(Remote Method Invocation,远程方法调用)是用Java在JDK1.2中实现的,它大大增强了Java开发分布式应用的能力。Java作为一种风靡一时的网络开发语言,其巨大的威力就体现在它强大的开发分布式网络应用的能力上,而RMI就是开发百分之百纯Java的网络分布式应用系统的核心解决方案之一。其实它可以被看作是RPC的Java版本。但是传统RPC并不能很好地应用于分布式对象系统。而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。
RMI概念:
RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制。使用这种机制,某一台计算机上的对象可以调用另外一台计算机上的对象来获取远程数据。RMI是Enterprise JavaBeans的支柱,是建立分布式Java应用程序的方便途径。在过去,TCP/IP套接字通讯是远程通讯的主要手段,但此开发方式没有使用面向对象的方式实现开发,在开发一个如此的通讯机制时往往令程序员感觉到乏味,对此RPC(Remote Procedure Call)应运而生,它使程序员更容易地调用远程程序,但在面对复杂的信息传讯时,RPC依然未能很好的支持,而且RPC未能做到面向对象调用的开发模式。针对RPC服务遗留的问题,RMI出现在世人面前,它被设计成一种面向对象的通讯方式,允许程序员使用远程对象来实现通信,并且支持多线程的服务,这是一次远程通讯的革命,为远程通信开辟新的里程碑。
RMI的开发步骤:
1)先创建远程接口及声明远程方法,注意这是实现双方通讯的接口,需要继承Remote。
2)开发一个类来实现远程接口及远程方法,值得注意的是实现类需要继承UnicastRemoteObject。
3)发布服务端,启动远程对象,Naming.bind("rmi://localhost:8888/RHello",rhello);
。
4)最后客户端查找远程对象,并调用远程方法,Naming.lookup("rmi://localhost:8888/RHello");
。
示例:
1)接口
package com.bh.test;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* @author cyq
*定义一个远程接口,该接口必须继承Remote接口,
*且需要远程调用的方法必须抛出RemoteException异常
*/
public interface Hello extends Remote {
public String helloWorld() throws RemoteException;
public String helloWorld2(String someBodyName) throws RemoteException;
}
2)接口实现类
package com.bh.test;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* @author cyq
*远程的接口的实现 需要继承UnicastRemoteObject
*/
public class HelloImpl extends UnicastRemoteObject implements Hello {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 因为UnicastRemoteObject的构造方法抛出了RemoteException异常,
* 因此这里默认的构造方法必须写,必须声明抛出RemoteException异常
* @throws RemoteException
*/
public HelloImpl() throws RemoteException {
}
public String helloWorld() throws RemoteException {
return "Hello World!";
}
public String helloWorld2(String name) throws RemoteException {
return "你好," + name;
}
}
3)发布服务
package com.bh.test;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* 创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。
*/
public class HelloServer {
public static void main(String args[]) {
try {
/*本地主机上的远程对象注册表Registry的实例,并指定端口为8888,这一步必不可少(Java默认端口是1099),
*必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上
**/
LocateRegistry.createRegistry(8888);
//把远程对象注册到RMI注册服务器上,并命名为Hello
//绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略)
Naming.bind("rmi://localhost:8888/Hello",new HelloImpl());
System.out.println("服务端启动。。。");
} catch (RemoteException e) {
System.out.println("创建远程对象发生异常!");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("发生重复绑定对象异常!");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("发生URL异常!");
e.printStackTrace();
}
}
}
4)客户端连接
package com.bh.test;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* @author cyq
*客户端测试,在客户端调用远程对象上的远程方法,并返回结果。
*/
public class HelloClient {
public static void main(String args[]){
try {
//在RMI服务注册表中查找名称为Hello的对象,并调用其上的方法
Hello rhello =(Hello) Naming.lookup("rmi://localhost:8888/Hello");
System.out.println(rhello.helloWorld());
System.out.println(rhello.helloWorld2("张三"));
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}