RMI

远程调用的时候,其核心就是远程调用其他主机上或者jvm上的类的相关方法,而远程调用过程中传输的数据内容是以序列化的形式传输的,必要的时候可能还会传输对象的引用等(当然也是以序列化的方式传输),传输的格式是基于JRMP协议的。

JRMP是 Java Remote Message Protocol 的缩写,java远程通信协议。主要就是为进程间、主机间java进程之间通信制定的协议,其是基于TCP的流量协议。

RMI中由三部分构成,Registry、Server 、Client

Server:
定义一个接口类,这个接口类要继承Remote接口,其中定义一个接口方法(此方法就是之后要远程调用的方法)并且该接口方法要爬出RemoteException异常,然后在其实现类中重写接口方法的实现,并且实现类要继承UnicastRemoteObject类(这个类的相关方法作用于导出对象(存根/Stub)的处理以及JRMP的处理,当然这里其实也不是说一定要继承这个类,也可以通过其他方法手动导出,但是后文中都是以继承UnicastRemoteObject类这种方法)

接口类Hello:

1
2
3
4
5
6
7
8
9
package  newrmi;  

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
//定义的之后需要被远程调用的方法
public String welcome(String name) throws RemoteException;
}

实现类Helloimp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.javatest;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;


public class Helloimp extends UnicastRemoteObject implements Hello{
public Helloimp() throws RemoteException {
}
//重写远程方法实现
@Override
public String welcome(String name) throws RemoteException {
return "hello"+name;
}
}

准备好之后还需要把这个远程对象绑定到Registry中,所以这里我们接下来先看下Registry实现

Registry:
使用LocateRegistry.createRegistry方法开启一个注册中心,然后server将刚刚准备的远程对象绑定到注册中心:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.javatest;

import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RmiRegistryAndServer {
public static void main(String args) {
try {
//开启远程注册中心
Registry registry = LocateRegistry.createRegistry(9999);
// (server)绑定对象到注册中心,并给他取名为hello
Hello hello = new Helloimp();
registry.bind("hellos",hello);
System.out.println("open port for rmi for 9999:hellos");
} catch (RemoteException | AlreadyBoundException e) {
e.printStackTrace();
}
}
}

Client:
客户端 去注册中心获取相关对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.javatest;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("localhost", 9999);
Hello hello = (Hello) registry.lookup("hellos");
System.out.println(hello.welcome("axin"));
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}

运行client:如下,可以看到相关方法被调用了:

以上是rmi过程中我们见到最多的常见,客户端向Registry lookup一个名称,最终实现对某个远程方法的调用。