RMI:
RMI是什么:Java的RMI远程调用是指,一个JVM中的代码可以通过网络实现远程调用另一个JVM的某个方法。RMI是Remote Method Invocation的缩写。
提供服务的一方我们称之为服务器,而实现远程调用的一方我们称之为客户端。
概念图:

客户端:
存根/桩(Stub):远程对象在客户端上的代理;
远程引用层(Remote Reference Layer):解析并执行远程引用协议;
传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。
服务端:
骨架(Skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法, 并接收方法执行后的返回值;
远程引用层(Remote Reference Layer):处理远程引用后向骨架发送远程方法调用;
传输层(Transport):监听客户端的入站连接,接收并转发调用到远程引用层。
注册表(Registry):
以URL形式注册远程对象,并向客户端回复对远程对象的引用。
详细实现:
可远程调用接口的实现:
package RMIProject;
import java.rmi.Remote;
import java.rmi.RemoteException;
// 定义一个远程接口,继承java.rmi.Remote接口
public interface HelloInterface extends Remote {
String Hello(String age) throws RemoteException;
}
可远程调用实现类的实现:
package RMIProject;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
// 远程接口实现类,继承UnicastRemoteObject类和Hello接口
public class HelloImp extends UnicastRemoteObject implements HelloInterface {
private static final long serialVersionUID = 1L;
protected HelloImp() throws RemoteException {
super(); // 调用父类的构造函数
}
@Override
public String Hello(String age) throws RemoteException {
return "Hello" + age; // 改写Hello方法
}
}
远程接口实现类必须继承UnicastRemoteObject类,用于生成 Stub(存根)和 Skeleton(骨架)。
Stub可以看作远程对象在本地的一个代理,囊括了远程对象的具体信息,客户端可以通过这个代理和服务端进行交互。
Skeleton可以看作为服务端的一个代理,用来处理Stub发送过来的请求,然后去调用客户端需要的请求方法,最终将方法执行结果返回给Stub。不过这部分会在创建对象的时候自动实现,如果对象继承了 UnicastRemoteObject,那在构造或导出过程中,RMI 运行时已经帮你把远程访问这套机制准备好了。
可远程调用对象的创建和绑定存根:
package RMIProject;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
// 服务端
public class RMIServer {
public static void main(String[] args) {
try {
HelloInterface h = new HelloImp(); // 创建远程对象HelloImp对象实例
LocateRegistry.createRegistry(1099); // 在服务器获取RMI服务注册器,在默认端口1099加载
Naming.rebind("rmi://localhost:1099/hello",h); // 绑定远程对象HelloImp到RMI服务注册器,./heelo路径是客户端查找它的标识
System.out.println("RMIServer start successful");
} catch (Exception e) {
e.printStackTrace();
}
}
}
也可以用下面这两行实现创建存根并绑定的逻辑
Registry registry = LocateRegistry.createRegistry(1099); //创建注册表
registry.rebind("hello",hello);//将远程对象注册到注册表里面,并且设置值为hello
客户端调用对应远程对象的实现:
package RMIProject;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
// 客户端
public class RMIClient {
public static void main(String[] args){
try {
HelloInterface h = (HelloInterface) Naming.lookup("rmi://localhost:1099/hello"); //通过对应路径寻找RMI实例远程对象,因此标出接口即可,只表示实现了哪些方法,而不关心具体实现
System.out.println(h.Hello("run......"));
}catch (MalformedURLException e) {
System.out.println("url格式异常");
} catch (RemoteException e) {
System.out.println("创建对象异常");
} catch (NotBoundException e) {
System.out.println("对象未绑定");
}
}
}
也可以用下面这串代码实现存根查找对象逻辑
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);//获取远程主机对象
// 利用注册表的代理去查询远程注册表中名为hello的对象
RemoteClass hello = (RemoteClass) registry.lookup("hello");
攻击注册中心:
后面涉及到cc链,还没怎么学懂,之后再补充