RMI原理一记远程调用
JDK1.5以前RMI调用是需要存根与代理的,1.2之后代理类好像看不到了.rmic只会生成存根类.
(1.2之前的JDK,我也没试过,我学习JAVA的时候,1.5就出来了)
开发RMI应用时,在进行bind对象时,会检测远程对象所对应的存根是否存在.这就是常发生的
*_stub.class找不到的问题. STUB用在客户端调用时,Rmi Registry为什么要检测他呢?
这是因为当客户端通过Naming.lookup获取这个远程对象时, Registry会把这个存根对象
或用于生成存根对象meta发给客户端,客户端通过这个存根对象或者通过meta生成存根对象.
进而进行运程对象的方法调用.
JDK1.5之后,有了新变化: Naming.lookup获取不再是这个存根对象,而是一个动态代理类.
这里只简单描述一下过程:
1. 获取的代理对象, 其InvocationHandler为RemoteObjectInvocationHandler:
public class RemoteObjectInvocationHandler extends RemoteObject implements InvocationHandler
2. RemoteObjectInvocationHandler的方法为:
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable{if (method.getDeclaringClass() == Object.class) {return invokeObjectMethod(proxy, method, args);} else {return invokeRemoteMethod(proxy, method, args);}}
这里把调用分为两部分:invokeObjectMethod和invokeRemoteMethod.我们主要看
invokeRemoteMethod:
private Object invokeRemoteMethod(Object proxy,Method method,Object[] args)throws Exception{try {if (!(proxy instanceof Remote)) {throw new IllegalArgumentException("proxy not Remote instance");}return ref.invoke((Remote) proxy, method, args,getMethodHash(method));} catch (Exception e) {if (!(e instanceof RuntimeException)) {Class<?> cl = proxy.getClass();try {method = cl.getMethod(method.getName(),method.getParameterTypes());} catch (NoSuchMethodException nsme) {throw (IllegalArgumentException)new IllegalArgumentException().initCause(nsme);}Class<?> thrownType = e.getClass();for (Class<?> declaredType : method.getExceptionTypes()) {if (declaredType.isAssignableFrom(thrownType)) {throw e;}}e = new UnexpectedException("unexpected exception", e);}throw e;}}
主要通过ref.invoke来进行调用,若打开rmic生成的存根类,你会发现调用方法也是一样的。
这个动态代理类,其实就是存根的替代品。这里ref的类为sun/rmi/server/UnicastRef.java
签名为:public class UnicastRef implements RemoteRef, 其invoke方法实现如下:
public Object invoke(Remote obj,Method method,Object[] params,long opnum)throws Exception{if (clientRefLog.isLoggable(Log.VERBOSE)) {clientRefLog.log(Log.VERBOSE, "method: " + method);}if (clientCallLog.isLoggable(Log.VERBOSE)) {logClientCall(obj, method);}Connection conn = ref.getChannel().newConnection();RemoteCall call = null;boolean reuse = true;/* If the call connection is "reused" early, remember not to* reuse again.*/boolean alreadyFreed = false;try {if (clientRefLog.isLoggable(Log.VERBOSE)) {clientRefLog.log(Log.VERBOSE, "opnum = " + opnum);}// create call contextcall = new StreamRemoteCall(conn, ref.getObjID(), -1, opnum);// marshal parameterstry {ObjectOutput out = call.getOutputStream();marshalCustomCallData(out);Class<?>[] types = method.getParameterTypes();for (int i = 0; i < types.length; i++) {marshalValue(types[i], params[i], out);}} catch (IOException e) {clientRefLog.log(Log.BRIEF,"IOException marshalling arguments: ", e);throw new MarshalException("error marshalling arguments", e);}// unmarshal returncall.executeCall();try {Class<?> rtype = method.getReturnType();if (rtype == void.class)return null;ObjectInput in = call.getInputStream();/* StreamRemoteCall.done() does not actually make use* of conn, therefore it is safe to reuse this* connection before the dirty call is sent for* registered refs.*/Object returnValue = unmarshalValue(rtype, in);/* we are freeing the connection now, do not free* again or reuse.*/alreadyFreed = true;/* if we got to this point, reuse must have been true. */clientRefLog.log(Log.BRIEF, "free connection (reuse = true)");/* Free the call's connection early. */ref.getChannel().free(conn, true);return returnValue;} catch (IOException e) {clientRefLog.log(Log.BRIEF,"IOException unmarshalling return: ", e);throw new UnmarshalException("error unmarshalling return", e);} catch (ClassNotFoundException e) {clientRefLog.log(Log.BRIEF,"ClassNotFoundException unmarshalling return: ", e);throw new UnmarshalException("error unmarshalling return", e);} finally {try {call.done();} catch (IOException e) {/* WARNING: If the conn has been reused early,* then it is too late to recover from thrown* IOExceptions caught here. This code is relying* on StreamRemoteCall.done() not actually* throwing IOExceptions.*/reuse = false;}}} catch (RuntimeException e) {/** Need to distinguish between client (generated by the* invoke method itself) and server RuntimeExceptions.* Client side RuntimeExceptions are likely to have* corrupted the call connection and those from the server* are not likely to have done so. If the exception came* from the server the call connection should be reused.*/if ((call == null) ||(((StreamRemoteCall) call).getServerException() != e)){reuse = false;}throw e;} catch (RemoteException e) {/** Some failure during call; assume connection cannot* be reused. Must assume failure even if ServerException* or ServerError occurs since these failures can happen* during parameter deserialization which would leave* the connection in a corrupted state.*/reuse = false;throw e;} catch (Error e) {/* If errors occurred, the connection is most likely not* reusable.*/reuse = false;throw e;} finally {/* alreadyFreed ensures that we do not log a reuse that* may have already happened.*/if (!alreadyFreed) {if (clientRefLog.isLoggable(Log.BRIEF)) {clientRefLog.log(Log.BRIEF, "free connection (reuse = " +reuse + ")");}ref.getChannel().free(conn, reuse);}}}
我们大致看出,在这里完成Socket通信.细节我就不描述了.知道是这么回事就成了。
RMI原理一记远程调用相关推荐
- RPC远程调用(RMI的方式实现RPC、HttpClient实现RPC远程调用)
RPC是什么? 2.3RPC实现的技术: 3:RMI实现RPC远程调用: 3.1RMI介绍 3.2RMI实现vip访问orders 3.2.1开发服务生产者(provider) 3.2.1.1创建or ...
- 《Spring技术内幕》学习笔记19——Spring RMI实现远程调用
1.Spring除了使用基于HTTP协议的远程调用方案,还为开发者提供了基于RMI机制的远程调用方法,RMI远程调用网络通信实现是基于TCP/IP协议完成的,而不是通过HTTP协议. 在Spring ...
- RMI原理揭秘之远程方法调用
接上:http://guojuanjun.blog.51cto.com/277646/1423392 这一次我们从学习RegistryImpl_Stub.java和RegistryImpl_Skel. ...
- 基于 Hessian 轻量级远程调用的原理及示例
1 简介 Hessian 是 Caucho 公司开发的一种基于二进制 RPC 协议(Remote Procedure Call protocol)的轻量级远程调用框架,其使用简单的方法提供了 RMI ...
- Java:RMI远程调用
首先服务器端定义服务接口和实现服务,然后服务器端利用RMI协议将服务发布到一个端口上.等待客户端调用. //定义服务接口,服务接口必须继承java.rmi.Remote,服务方法必须抛出java.rm ...
- 【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )
文章目录 一.进程注入原理 二.远程调用流程 ( 获取 so 动态库地址 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 ) 一.进程注入原理 调试进程 At ...
- 远程调用:远程过程调用(RPC)和远程方法调用(RMI)
远程调用包括远程过程调用(RPC)和远程方法调用(RMI) 1.请求-应答协议 请求-应答协议描述了一个基于消息传递的范型,支持消息双向传输. 涉及三个通信原语 (1)doOperation:向指定的 ...
- 远程调用-rmi远程连接被拒绝
[问题背景] 本项目的导入导出功能是异步实现的,即: 第一步:前台页面先点击"导入"."导出"按钮,后台给任务表Task插入一条队列任务: 第二步:Linux主 ...
- 分布式系统架构的远程调用(RESTFul、RPC)和CAP原理
文章目录 分布式系统的远程调用 RestFul接口 RPC协议 RestFul和RPC的区别 分布式系统的CAP原理 分布式系统的远程调用 在微服务架构中,通常存在多个服务之间的远程调用的需求.远程调 ...
最新文章
- 在开发游戏过程中遇到的一些错误(很基础的错误)
- mingw编译ffmpeg 错误:Unknown option --enable-memalign-hack
- linux crontab 管理,linux crontab 命令详解
- Java中外部类访问内部类的方法
- 不可多得的Javascript(AJAX)开发工具 - Aptana
- pyqt5与html数据交互原理,pyqt5与本地html进行js交互
- 在系统中用etcd实现服务注册和发现
- Active Report 紙張設置小結
- Redis底部的几种存储结构(sds、dict、ziplist、intset、skiplist)
- Web 开发中使用了 Vim 作为主编辑器之后......
- dbentry访问带密码的Access
- get_posts 函数 | wordpress
- centos7全盘备份到本地_centos7磁盘备份和还原
- 手把手教你获得CSDN徽章:CSDN IT冷知识 每日一练
- windows便签工具在哪,怎么在便签上保存工作提醒事项
- 全局变量、函数原型和Guard macro
- JavaUUID的理解
- 报表引擎终于做出来了!!!!!参考了根兄的文档。
- 整数二分详解---yxc
- 教育培训python
热门文章
- dicom是指_dicom格式是什么
- android byte转string_唠点儿你不一定知道的Android小知识
- 判断深度学习模型的稳定性_基于深度学习的三维模型检索算法研究
- 在linux中 如何创建磁盘配额,如何在Linux系统中配置磁盘配额?
- python的os库_os库(python)—总结
- thinkphp5 mysql助手_ThinkPHP5-数据库基本操作
- 一个简单的EJB-Session Bean实例
- 什么是jQuery?
- 前端chrome浏览器调试总结??
- 大数据学习笔记:创建与配置虚拟机[Ubuntu + CentOS]