1.RMI
RMI是个典型的为java定制的远程通信协议,我们都知道,在single vm中,我们可以通过直接调用java object instance来实现通信,那么在远程通信时,如果也能按照这种方式当然是最好了,这种远程通信的机制成为RPC(Remote Procedure Call),RMI正是朝着这个目标而诞生的。
来看下基于RMI的一次完整的远程通信过程的原理:
- 1. 客户端发起请求,请求转交至RMI客户端的stub类;
- 2. stub类将请求的接口、方法、参数等信息进行序列化;
- 3. 基于socket将序列化后的流传输至服务器端;
- 4. 服务器端接收到流后转发至相应的skelton类;
- 5. skelton类将请求的信息反序列化后调用实际的处理类;
- 6. 处理类处理完毕后将结果返回给skelton类;
- 7. Skelton类将结果序列化,通过socket将流传送给客户端的stub;
- 8. stub在接收到流后反序列化,将反序列化后的Java Object返回给调用者。
2.简单例子
PersonService.java
package rmi.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
//此为远程对象调用的接口,必须继承Remote类
public interface PersonService extends Remote {
public String getPersonName(int id) throws RemoteException;
}
PersonServiceImpl.java
package rmi.serviceImpl;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import rmi.service.PersonService;
public class PersonServiceImpl extends UnicastRemoteObject implements PersonService {
public PersonServiceImpl() throws RemoteException {
super();
}
@Override
public String getPersonName(int id) throws RemoteException {
String returnName;
if (0 == id) {
returnName = "张三";
} else if (1 == id) {
returnName = "李四";
} else if (2 == id) {
returnName = "王五";
} else {
returnName = "不存在";
}
System.out.println("------------getPersonName(" + id + ")------------");
return returnName;
}
}
ReremoServer.java
package rmi.remote;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import rmi.service.PersonService;
import rmi.serviceImpl.PersonServiceImpl;
public class ReremoServer {
public static void main(String[] args) {
try {
PersonService personService = new PersonServiceImpl();
// 注册通讯端口
LocateRegistry.createRegistry(6600);
// 注册通讯路径
Naming.rebind("rmi://localhost:6600/PersonService", personService);
System.out.println("------服务启动成功------");
} catch (Exception e) {
e.printStackTrace();
}
}
}
ReremoClient.java
package rmi.remote;
import java.rmi.Naming;
import rmi.service.PersonService;
public class ReremoClient {
public static void main(String[] args) {
try {
// 调用远程对象,注意RMI路径与接口必须与服务器配置一致
PersonService personService = (PersonService) Naming.lookup("rmi://localhost:6600/PersonService");
for (int i = 0; i < 5; i++) {
String name = personService.getPersonName(i);
System.out.println("name:" + name);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
3.运行结果
4.如何生成stub文件