什么是rmi
RMI,是Remote Method Invocation(远程方法调用)的缩写,即在一个JVM中java程序调用在另一个远程JVM中运行的java程序,这个远程JVM既可以在同一台实体机上,也可以在不同的实体机上,两者之间通过网络进行通信。java RMI封装了远程调用的实现细节,进行简单的配置之后,就可以如同调用本地方法一样,比较透明地调用远端方法。
RMI包括以下三个部分:
- Registry: 提供服务注册与服务获取。即Server端向Registry注册服务,比如地址、端口等一些信息,Client端从Registry获取远程对象的一些信息,如地址、端口等,然后进行远程调用。
- Server: 远程方法的提供者,并向Registry注册自身提供的服务
- Client: 远程方法的消费者,从Registry获取远程方法的相关信息并且调用
jdk中java.rmi包简介
Remote
一个interface,这个interface中没有声明任何方法。只有定义在“remote interface",即继承了Remote
的接口中的方法,才可以被远程调用。
RemoteException
RemoteException是所有在远程调用中所抛出异常的超类,所有能够被远程调用的方法声明,都需要抛出此异常
Naming
提供向注册中心保存远程对象引用或者从注册中心获取远程对象引用的方法。这个类中的方法都是静态方法,每一个方法都包含了一个类型为String的name参数, 这个参数是URL格式,形如://host:port/name
Registry
一个interface, 其功能和Naming
类似,每个方法都有一个String类型的name参数,但是这个name不是URL格式,是远程对象的一个命名。Registry的实例可以通过方法LocateRegistry.getRegistry()
获得
LocateRegistry
用于获取到注册中心的一个连接,这个连接可以用于获取一个远程对象的引用。也可以创建一个注册中心。
RemoteObject
重新覆写了Object
对象中的equals,hashCode,toString方法,从而可以用于远程调用
UnicastRemoteObject
用于RMI Server中导出一个远程对象并获得一个stub。这个stub封装了底层细节,用于和远程对象进行通信。
Unreferenced
一个interface, 声明了方法:void unreferenced()
如果一个远程队形实现了此接口,则这个远程对象在没有任何客户端引用的时候,这个方法会被调用。
rmi使用
在这一节,我们将从头开始写一个简单的RMI示例,实现输入名字,返回“Hello, XXX"的工程。创建一个完整的远程调用,我们分为以下几步:
- 定义一个远程接口,这个接口需要继承
Remote
,并且接口中的每一个方法都需要抛出RemoteException
异常 - 开发远程接口的实现类
- Registry的创建
- RMI Server的创建
- RMI Client的创建
定义一个远程接口
package com.luckyqiao.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteHello extends Remote {
String sayHello(String name) throws RemoteException;
}
开发远程接口的实现类
package com.luckyqiao.rmi;
import java.rmi.RemoteException;
public class RemoteHelloImpl implements RemoteHello {
public String sayHello(String name) throws RemoteException {
return String.format("Hello, %s!", name);
}
}
Registry 的创建
package com.luckyqiao.rmi;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.concurrent.CountDownLatch;
public class RegistryServer {
public static void main(String[] args) throws InterruptedException{
try {
LocateRegistry.createRegistry(8000); //Registry使用8000端口
} catch (RemoteException e) {
e.printStackTrace();
}
CountDownLatch latch=new CountDownLatch(1);
latch.await(); //挂起主线程,否则应用会退出
}
}
RMI Server 的创建
package com.luckyqiao.rmi;
import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class RMIServer {
public static void main(String[] args) {
RemoteHello remoteHello = new RemoteHelloImpl();
try {
RemoteHello stub = (RemoteHello) UnicastRemoteObject.exportObject(remoteHello, 4000); //导出服务,使用4000端口
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 8000); //获取Registry
registry.bind("hello", stub); //使用名字hello,将服务注册到Registry
} catch (AlreadyBoundException | IOException e) {
e.printStackTrace();
}
}
}
RMI Client的创建
package com.luckyqiao.study.rmi;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIClient {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 8000); //获取注册中心引用
RemoteHello remoteHello = (RemoteHello) registry.lookup("hello"); //获取RemoteHello服务
System.out.println(remoteHello.sayHello("World")); //调用远程方法
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
}
}
原理
未完待续