我们先来看看Java RMI的定义:
RMI(Remote Method Invocation,远程方法调用)是用Java在JDK1.2中实现的,它大大增强了Java开发分布式应用的能力。Java作为一种风靡一时的网络开发语言,其巨大的威力就体现在它强大的开发分布式网络应用的能力上,而RMI就是开发百分之百纯Java的网络分布式应用系统的核心解决方案之一。其实它可以被看作是RPC的Java版本。但是传统RPC并不能很好地应用于分布式对象系统。而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。
RMI远程调用步骤
RMI的交互图:
RMI由3个部分构成,第一个是rmiregistry(JDK提供的一个可以独立运行的程序,在bin目录下),第二个是server端的程序,对外提供远程对象,第三个是client端的程序,想要调用远程对象的方法。
首先,先启动rmiregistry服务,启动时可以指定服务监听的端口,也可以使用默认的端口(1099)。
其次,server端在本地先实例化一个提供服务的实现类,然后通过RMI提供的Naming/Context/Registry(下面实例用的Registry)等类的bind或rebind方法将刚才实例化好的实现类注册到rmiregistry上并对外暴露一个名称。
最后,client端通过本地的接口和一个已知的名称(即rmiregistry暴露出的名称)再使用RMI提供的Naming/Context/Registry等类的lookup方法从RMIService那拿到实现类。这样虽然本地没有这个类的实现类,但所有的方法都在接口里了,便可以实现远程调用对象的方法了。
存根和骨干网的具体通信过程:
方法调用从客户对象经存根(stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,然后再次经传输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。
存根扮演着远程服务器对象的代理的角色,使该对象可被客户激活。
远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。
传输层管理实际的连接,并且追踪可以接受方法调用的远程对象。
骨干网完成对服务器对象实际的方法调用,并获取返回值。
返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,存根获得返回值。
JAVA RMI简单示例
本示例是client端调用server端远程对象的加减法方法,具体步骤为:
1. 定义一个远程接口
import java.rmi.Remote; import java.rmi.RemoteException; /** * 必须继承Remote接口。 * 所有参数和返回类型必须序列化(因为要网络传输)。 * 任意远程对象都必须实现此接口。 * 只有远程接口中指定的方法可以被调用。 */ public interface IRemoteMath extends Remote { // 所有方法必须抛出RemoteException public double add(double a, double b) throws RemoteException; public double subtract(double a, double b) throws RemoteException; }
(学习视频分享:java视频教程)
2. 远程接口实现类
import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import remote.IRemoteMath; /** * 服务器端实现远程接口。 * 必须继承UnicastRemoteObject,以允许JVM创建远程的存根/代理。 */ public class RemoteMath extends UnicastRemoteObject implements IRemoteMath { private int numberOfComputations; protected RemoteMath() throws RemoteException { numberOfComputations = 0; } @Override public double add(double a, double b) throws RemoteException { numberOfComputations++; System.out.println("Number of computations performed so far = " + numberOfComputations); return (a+b); } @Override public double subtract(double a, double b) throws RemoteException { numberOfComputations++; System.out.println("Number of computations performed so far = " + numberOfComputations); return (a-b); } }
3. 服务器端
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import remote.IRemoteMath; /** * 创建RemoteMath类的实例并在rmiregistry中注册。 */ public class RMIServer { public static void main(String[] args) { try { // 注册远程对象,向客户端提供远程对象服务。 // 远程对象是在远程服务上创建的,你无法确切地知道远程服务器上的对象的名称, // 但是,将远程对象注册到RMI Registry之后, // 客户端就可以通过RMI Registry请求到该远程服务对象的stub, // 利用stub代理就可以访问远程服务对象了。 IRemoteMath remoteMath = new RemoteMath(); LocateRegistry.createRegistry(1099); Registry registry = LocateRegistry.getRegistry(); registry.bind("Compute", remoteMath); System.out.println("Math server ready"); // 如果不想再让该对象被继续调用,使用下面一行 // UnicastRemoteObject.unexportObject(remoteMath, false); } catch (Exception e) { e.printStackTrace(); } } }
4. 客户端
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import remote.IRemoteMath; public class MathClient { public static void main(String[] args) { try { // 如果RMI Registry就在本地机器上,URL就是:rmi://localhost:1099/hello // 否则,URL就是:rmi://RMIService_IP:1099/hello Registry registry = LocateRegistry.getRegistry("localhost"); // 从Registry中检索远程对象的存根/代理 IRemoteMath remoteMath = (IRemoteMath)registry.lookup("Compute"); // 调用远程对象的方法 double addResult = remoteMath.add(5.0, 3.0); System.out.println("5.0 + 3.0 = " + addResult); double subResult = remoteMath.subtract(5.0, 3.0); System.out.println("5.0 - 3.0 = " + subResult); }catch(Exception e) { e.printStackTrace(); } } }
结果如下:
server端
client端
参考:https://blog.csdn.net/xinghun_4/article/details/45787549
相关推荐:java入门教程
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!