java安全-RMI
Java安全 - RMI
1、RMI原理浅析
RMI
(Remote Method Invocation
) 远程方法调用,是允许运行在一个JVM
中的对象调用另一个JVM
中的对象方法。两台虚拟机可以是同一台宿主机的不同进程,也可以运行在网络不同主机中,RMI
基本结构是基于行为定义
和行为实现
分离原则设计的,即用于定义行为的接口和行为的实现代码分离,且允许在不同JVM
中运行。
行为定义
和行为实现
在RMI
中体现在行为定义
的代码写在服务端中继承了Remote
的接口里,且允许不同的两个类实现同一个远程服务接口;而具体的行为实现
一个类在服务端实现具体行为,另一个类在客户端作为远程服务代理提供客户端调用远程方法。
RMI分为三个部分:Server
、Client
、Registry
其中介绍一下Registry的作用,Registry是一个注册表,其中存放了远程对象的(ip、端口、标识符),它可以与服务端放在一起,也可以独立放在另一台JVM
中。Client
在调用远程方法时,并不直接与Server
通信远程调用方法不直接与服务端通信,会通过名称服务Naming
在Registry
中查找注册的远程对象,由Registry
提供远程对象的引用,其中提供了主机名,端口以及标识符,客户端再通过这些引用信息与远程服务端通过socket连接。
为什么使用Registry
,其中一个很重要的原因是方便提供多服务端的远程服务,一个Registry
中可以提供不同服务器的远程对象引用。
图中提及bind
和rebind
两个方法,其实他们是不同的类方法,Registry.bind
和Naming.rebind
bind
使用注册表进行绑定,由于该方法直接使用了保留有注册表信息的类,不需要实现完整的RMI URL
。rebind
,使用java中的Naming
名称服务进行绑定,在RMI
中,名称服务不仅仅提供注册表的路径查询,所以需要指明完整的RMI URL
。
例如
//通过注册表绑定远程对象引用
registry.rebind("Hello", remoteObj);
//通过Naming绑定远程对象
Naming.bind("rmi://127.0.0.1:1099/remote", remoteObj);
服务端实现
编写远程对象的接口,声明远程对象的方法,接口需要继承Remote
类
public interface RemoteObj extends Remote {
public String Hello() throws RemoteException;
}
实现远程对象接口,需要继承UnicastRemoteObject
类
public class RemoteObjImpl extends UnicastRemoteObject implements RemoteObj {
protected RemoteObjImpl() throws RemoteException {
System.out.println("RemoteObjImpl的构造方法");
}
@Override
public String Hello() {
return "Hello World";
}
}
服务端启动以及创建注册表
public class RMIServer {
public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {
//创建远程对象
RemoteObj remoteObj = new RemoteObjImpl();
//创建注册表,设置端口1099
Registry registry = LocateRegistry.createRegistry(1099);
//通过注册表绑定远程对象引用
registry.rebind("Hello", remoteObj);
//通过Naming绑定远程对象
// Naming.bind("rmi://127.0.0.1:1099/remote", remoteObj);
}
}
客户端实现
获取需要调用的远程对象的接口,这里直接将接口写入客户端中模拟
public interface RemoteObj extends Remote {
public String Hello();
}
客户端调用远程方法
public class RMIClient {
public static void main(String[] args) throws MalformedURLException, NotBoundException, RemoteException {
Registry registry = LocateRegistry.getRegistry("localhost",1099);
// RemoteObj remoteObj = (RemoteObj) Naming.lookup("rmi://127.0.0.1:1099/Hello");
RemoteObj remoteObj = (RemoteObj) registry.lookup("Hello");
String ret = remoteObj.Hello();
System.out.println(ret);
}
}
server
client
接下来会继续更新(由于源码分析部分篇幅过长,单独写了一篇 https://www.cnblogs.com/p1a0m1a0/p/17071632.html)