RMI(Remote Method Invocation)
RMI简介
RMI(Remote Method Invocation)是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口, 客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法。 RMI依赖的通信协议为JRMP(Java Remote Message Protocol ,Java 远程消息交换协议), 该协议为Java定制,要求服务端与客户端都为Java编写。这个协议就像HTTP协议一样, 规定了客户端和服务端通信要满足的规范。在RMI中对象是通过序列化方式进行编码传输的。
RMI demo
这里以远程调用一个通过用户名查询用户信息(假如一个用户名对应一个唯一用户)为例,实现一个简单的rmi流程。
- User对象-->rmi的远程对象 (必须可以被序列化)
远程方法调用,会涉及参数的传递和执行结果的返回。参数或者返回值可以是基本数据类型,当然也有可能是对象的引用。所以这些需要被传输的对象必须可以被序列化,这要求相应的类必须实现
java.io.Serializable接口,否则会抛出java.io.NotSerializableException。
// Serializable接口
public class User implements Serializable {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
- 方法-->rmi方法
任何可以被远程调用方法的对象必须实现
java.rmi.Remote接口,远程对象的实现类必须继承UnicastRemoteObject类。如果不继承UnicastRemoteObject类,则需要手工初始化远程对象,在远程对象的构造方法的调用UnicastRemoteObject.exportObject()静态方法
接口方法
//remote接口
public interface UserRegistryFacade extends Remote {
User queryUser(String name) throws RemoteException;
}
服务端实现类
//继承UnicastRemoteObject类
public class UserRegistryFacadeImpl extends UnicastRemoteObject implements UserRegistryFacade {
public UserRegistryFacadeImpl() throws RemoteException {
super();
}
@Override
public User queryUser(String name) {
System.out.println("====收到请求====");
return new User(name, 30);
}
}
- server端注册
try {
// 本地主机上的远程对象注册表Registry的实例,默认端口1099
Registry registry = LocateRegistry.createRegistry(9999);
// 创建一个远程对象
UserRegistryFacadeImpl userService = new UserRegistryFacadeImpl();
// 把远程对象注册到RMI注册服务器上,并命名为queryUser
registry.rebind("userService", (UserRegistryFacadeImpl) userService);
System.out.println("======= 启动RMI服务成功! =======");
} catch (RemoteException e) {
e.printStackTrace();
}
- client端调用
try {
String remoteUrl = "rmi://other:9999/userService";
UserRegistryFacade userService = (UserRegistryFacade) Naming.lookup(remoteUrl);
User user = userService.queryUser("张三");
System.out.println("=======> " + user != null ? user.toString() : "" + " <=======");
} catch (NotBoundException | RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
- 真实调用过程