RPC和RMI的区别
RPC | RMI |
客户端通过网络请求调用某种服务 | 在客户端Java虚拟机上的对象像调用本地对象一样调用服务端java 虚拟机中的对象上的方法 |
Demo结构
接口API
//RMI要用Remote接口实现
public interface FirstInterface extends Remote {
//所有Remote都需要抛出exception
String first(String name) throws RemoteException;
}
服务端
1、实现远程服务接口
/**
* 需要实现远程服务接口 直接实现 or 间接实现
*/
public class FirstRMIImpl extends UnicastRemoteObject implements FirstInterface, Remote {
//构造方法需要抛出remoteException异常
public FirstRMIImpl() throws RemoteException{
super();
}
//不会创建RMI服务,可以继承UnicastRemoteObject类型
//所有方法都要抛出异常,包括构造方法
@Override
public String first(String name) throws RemoteException {
System.out.println("客户端请求参数是:"+name);
return "你好,"+name;
}
}
UnicastRemoteObject 可以将当前对象暴露出来,让其他客户端调用
2、提供服务,注册到注册中心上
public class Main {
//RMI在注册中心创建时,会自动创建一个子线程,升级为守护线程,长期运行,不会挂掉
public static void main(String[] args) {
try {
System.out.println("服务器启动中!");
FirstRMIImpl firstRMI = new FirstRMIImpl();
System.out.println(LocateRegistry.getRegistry(9999));
//注册到 注册中心上 正整数<655536
LocateRegistry.createRegistry(9999);
System.out.println(LocateRegistry.getRegistry(9999));
//绑定服务到注册中心,格式:rmi://ip:port/别名
//命名重复会抛异常:已绑定异常
// Naming.bind("rmi://localhost:9999/first",firstRMI);
//重新绑定一个服务到注册中心,命名冲突:直接覆盖,不会抛出异常
Naming.rebind("rmi://localhost:9999/first",firstRMI);
System.out.println("服务器启动完毕!");
//进程关闭
} catch (Exception e) {
e.printStackTrace();
}
}
}
绑定服务到注册中心,有两种方法:
1、Naming.bind() 如果命名冲突,会抛出异常
2、Naming.rebind() 如果命名冲突,也不会抛出异常,会直接覆盖
服务注册到注册中心的格式:rmi://ip:port/别名
客户端
1、在注册中心寻找服务 并 调用
public class ClientMainClass {
public static void main(String[] args) {
//创建代理对象
FirstInterface first=null;
try {
//通过名字找服务,并自动创建代理对象
//类型时Object,对象一定是Proxy的子类型,且实现了服务接口
first= (FirstInterface) Naming.lookup("rmi://localhost:9999/first");
String str = first.first("janejanejane");
System.out.println("对象类型:"+first.getClass().getName());
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Naming.lookup()寻找服务