RMI (Remote Method Invocation,远程方法调用)是JAVA一组拥护开发分布式应用程序的API,用于不同虚拟机间的通信,核心是远程对象
1、客户端调用辅助对象stub上方法
2、stub对调用信息(变量、方法)打包,网络发给服务端辅助对象
3、(1.2前)skeleton将stub送来的信息解包,找到被调方法的对象及本身
4、调用服务端对象上的方法,将结果返回给skeleton、打包、给stub
5、stub解包,返给客户端对象,获取返回值
可以把stub理解为本地的一个代理对象,客户端不知道server的存在,
解决方案一:引用传递更改为值传递
将对象序列化为字节,使用字节副本在客户端、服务器间传递,一个虚拟机对该值的修改不影响其他主机的数据,问题:对象嵌套引用造成序列化嵌套,数据量激增
能不能被序列化要满足下面任一条件:1、java基本类型,2、实现Serializable接口,3、容器类中的对象可以序列化,容器也可以序列化,4、子类可序列化,其可序列化
当远程主机调用本地主机方法时,通过本地主机查询引用对应的对象;对象共享、一变都收影响
RMI参数传递和结果返回的三种机制:
1、简单类型:按值传递、传递数据拷贝;2、(实现了Remote接口的)远程对象引用、以远程对象的引用传递;3、(未实现Remote接口)远程对象引用,按值传递,通过序列化传递副本
调用远程对象方法前需远程对象的引用,如何获取呐?首先咱们把“将远程对象的发现”类比于IP地址的发现
实际生活中网络通过IP地址来定位网站,这有一个映射的过程,在DNS(Domain Name System)域名系统中通过域名来查找对应的IP地址来访问服务器,这里IP相当于远程对象的引用,DNS相当于一个注册表Registry,域名在RMI中相当于远程对象的标识符,客户端通过提供远程对象的标识符访问注册表、得到远程对象的引用;标识符:
名称是URL形式的,类似于http的URL,schema是rmi,rmi://host:port/name,host注册表运行的注解,port接收调用的端口,name是标识对象的简单名称,主机和端口可选、依次默认本地、1099
服务器端:
远程对象:实现java.rmi.Remote接口或继承java.rmi.Remote接口的接口
在远程接口中声明的方法才能被远程调用
注意事项:
1、子接口中方法必须抛出java.rmi.RemoteException异常(使用RMI时可能抛出的大多数异常的父类)
2、子接口的实现类直接、间接继承java.rmi.server.UnicastRemoteObject(提供了很多支持RMI的方法,这些方法可以通过JRMP协议导出一个远程对象的引用并动态代理构建可以和远程对象交互的stub对象)
public interface UserHandler extends Remote { String getUserName(int id) throws RemoteException; }
实体类:序列化、serialVersionUID(后面客户端对应上)
public class User implements Serializable { // 该字段必须存在 private static final long serialVersionUID = 42L; // setter和getter可以没有 String name; int id; public User(String name, int id) { this.name = name; this.id = id; } }
实现类:
public class UserHandlerImpl extends UnicastRemoteObject implements UserHandler { // 该构造期必须存在,因为集继承了UnicastRemoteObject类,其构造器要抛出RemoteException public UserHandlerImpl() throws RemoteException { super(); } @Override public String getUserName(int id) throws RemoteException { return "开挂的人生"; } }
运行远程对象:
UserHandler userHandler = null; userHandler = new UserHandlerImpl(); Naming.rebind("user", userHandler);//通过名称映射到该远程对象的引用,客户端通过该名称获取该远程对象的引用。
注册表:
运行exe
JAVA_HOME下bin目录下有一个rmiregistry.exe程序,在你的程序的classpath下运行该程序
编程运行
通过java.rmi.registry包中的Registry接口和以及其实现类LocateRegistry来完成的
客户端:
UserHandler handler = (UserHandler) Naming.lookup("user");//通过名称获取远程对象引用 int count = handler.getUserCount(); String name = handler.getUserName(1);
小结:
不知道怎么就学到这了?大概是序列化吧,时间紧任务重,这块还是需要写个小结的,RMI用于分布式方法调用,借助于remote远程调用,过程中存在一些隐患抛出异常,分布式中你去找哪个户下的哪个窗呐?通过名字还有serialVersionUID在注册表里面找,想起了Dubbo、springCloud
有错误之处欢迎指出,共同交流、一起进步、为中国造芯片!
百科渡一下
注:DNS:因特网的一项核心服务,它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串【源】
JRMP:java remote method protocol,Java远程方法协议,JAVA特有的基于流的协议