RMI是J2EE技术规范之一,英文全称Remote Method Invocation(即远程方法调用)。远程方法调用是一种同一计算机不同Java研发软件系统之间或不同计算机不同Java研发软件系统之间通过调用对方远程方法启动对方进程进而实现交互的一种机制,这种机制为开发分布式应用程序带来了极大的方便。
RMI技术的应用通常包括在两个独立的应用程序中:服务端应用程序和客户端应用程序。
服务端应用程序:
RMI典型的服务端代码将创建多个远程对象,使这些远程对象能够被引用,然后等待客户端调用这些远程对象中的方法,其实现步骤如下:
1、自定义远程接口
示例代码如下:
package com.ghj.packageofrmi; import java.rmi.Remote; import java.rmi.RemoteException; /** * 定义一个继承Remote接口的远程接口。 * * @author 高焕杰 */ public interface IHelloWord extends Remote { /** * 获取信息 * * @author 高焕杰 */ String getMsg() throws RemoteException; }
在 Java RMI服务端,远程对象是自定义远程接口实现类的实例, 该远程接口声明每个要远程调用的抽象方法。
自定义远程接口特点:
a、该接口必须继承java.rmi.Remote接口;
b、该接口中的每个抽象方法必须抛出RemoteException异常或RemoteException 的父类异常;
2、自定义远程接口实现类
示例代码如下:
package com.ghj.packageofrmi; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; /** * 远程接口实现类。 * * @author 高焕杰 */ public class HelloWordImp extends UnicastRemoteObject implements IHelloWord{ private static final long serialVersionUID = -918923487973606075L; /** * 远程接口实现类构造方法 * * @author 高焕杰 */ public HelloWordImp() throws RemoteException { } /** * 获取信息 * * @author 高焕杰 */ @Override public String getMsg() throws RemoteException { return "Hello World!"; } }
自定义远程接口实现类特点:
a、该实现类必须实现自定义远程接口内的每个远程抽象方法;
b、该实现类必须继承java.rmi.UnicastRemoteObject类。UnicastRemoteObject类可以让服务端远程对象与客户端建立一对一的连接;
c、由于UnicastRemoteObject类中默认构造方法抛出RemoteException异常,因此该实现类中默认的构造方法必须显示地写出来并且该构造方法必须声明抛出RemoteException异常,别忘了子类构造方法要与父类参数列表相同的构造方法一致,父类无参构造方法抛出了RemoteException异常,那么子类无参构造方法也需要抛出抛出RemoteException异常;
d、该实现类也可以含有其它非远程接口定义的抽象方法或非接口方法(即实现类内部自定义的方法,这些方法不能使用@Override进行注释),但客户端不能调用这些新增的方法(别忘了,这些方法并不是自定义远程接口的抽象方法)。
3、服务端RMI类
示例代码如下:
package com.ghj.packageoftest; import java.net.MalformedURLException; import java.rmi.AlreadyBoundException; import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import com.ghj.packageofrmi.HelloWordImp; import com.ghj.packageofrmi.IHelloWord; /** * 启动RMI服务 * * @author 高焕杰 */ public class StartRMIServer { public static void main(String args[]) { try { int registryPort = 8888;//注册表上接受请求的端口号 //通过IHelloWord接口实现类声明并创建该接口对象以作为远程对象 。 IHelloWord helloWord = new HelloWordImp(); //为RMI服务注册表设置端口号,这一步不可缺,否则无法将远程对象绑定远程注册表上 。 LocateRegistry.createRegistry(registryPort); //将serviceName(即服务名称)和远程接口变量绑定,绑定的URL标准格式为“rmi://host:registryPort/serviceName”,也可以“//host:registryPort/serviceName” Naming.bind("rmi://localhost:" + registryPort + "/rmiDemo",helloWord); // Naming.bind("//localhost:" + registryPort + "/rmiDemo",helloWord); System.out.println("RMI服务成功启动!"); } catch (RemoteException e) { System.err.println("远程对象创建失败!"); e.printStackTrace(); } catch (AlreadyBoundException e) { System.err.println("发生重复绑定远程对象异常!"); e.printStackTrace(); } catch (MalformedURLException e) { System.err.println("绑定的URL不正确!"); e.printStackTrace(); } } }
客户端应用程序: