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原理一记远程调用相关推荐

  1. 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 ...

  2. 《Spring技术内幕》学习笔记19——Spring RMI实现远程调用

    1.Spring除了使用基于HTTP协议的远程调用方案,还为开发者提供了基于RMI机制的远程调用方法,RMI远程调用网络通信实现是基于TCP/IP协议完成的,而不是通过HTTP协议. 在Spring ...

  3. RMI原理揭秘之远程方法调用

    接上:http://guojuanjun.blog.51cto.com/277646/1423392 这一次我们从学习RegistryImpl_Stub.java和RegistryImpl_Skel. ...

  4. 基于 Hessian 轻量级远程调用的原理及示例

    1 简介 Hessian 是 Caucho 公司开发的一种基于二进制 RPC 协议(Remote Procedure Call protocol)的轻量级远程调用框架,其使用简单的方法提供了 RMI ...

  5. Java:RMI远程调用

    首先服务器端定义服务接口和实现服务,然后服务器端利用RMI协议将服务发布到一个端口上.等待客户端调用. //定义服务接口,服务接口必须继承java.rmi.Remote,服务方法必须抛出java.rm ...

  6. 【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )

    文章目录 一.进程注入原理 二.远程调用流程 ( 获取 so 动态库地址 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 ) 一.进程注入原理 调试进程 At ...

  7. 远程调用:远程过程调用(RPC)和远程方法调用(RMI)

    远程调用包括远程过程调用(RPC)和远程方法调用(RMI) 1.请求-应答协议 请求-应答协议描述了一个基于消息传递的范型,支持消息双向传输. 涉及三个通信原语 (1)doOperation:向指定的 ...

  8. 远程调用-rmi远程连接被拒绝

    [问题背景] 本项目的导入导出功能是异步实现的,即: 第一步:前台页面先点击"导入"."导出"按钮,后台给任务表Task插入一条队列任务: 第二步:Linux主 ...

  9. 分布式系统架构的远程调用(RESTFul、RPC)和CAP原理

    文章目录 分布式系统的远程调用 RestFul接口 RPC协议 RestFul和RPC的区别 分布式系统的CAP原理 分布式系统的远程调用 在微服务架构中,通常存在多个服务之间的远程调用的需求.远程调 ...

最新文章

  1. 在开发游戏过程中遇到的一些错误(很基础的错误)
  2. mingw编译ffmpeg 错误:Unknown option --enable-memalign-hack
  3. linux crontab 管理,linux crontab 命令详解
  4. Java中外部类访问内部类的方法
  5. 不可多得的Javascript(AJAX)开发工具 - Aptana
  6. pyqt5与html数据交互原理,pyqt5与本地html进行js交互
  7. 在系统中用etcd实现服务注册和发现
  8. Active Report 紙張設置小結
  9. Redis底部的几种存储结构(sds、dict、ziplist、intset、skiplist)
  10. Web 开发中使用了 Vim 作为主编辑器之后......
  11. dbentry访问带密码的Access
  12. get_posts 函数 | wordpress
  13. centos7全盘备份到本地_centos7磁盘备份和还原
  14. 手把手教你获得CSDN徽章:CSDN IT冷知识 每日一练
  15. windows便签工具在哪,怎么在便签上保存工作提醒事项
  16. 全局变量、函数原型和Guard macro
  17. JavaUUID的理解
  18. 报表引擎终于做出来了!!!!!参考了根兄的文档。
  19. 整数二分详解---yxc
  20. 教育培训python

热门文章

  1. dicom是指_dicom格式是什么
  2. android byte转string_唠点儿你不一定知道的Android小知识
  3. 判断深度学习模型的稳定性_基于深度学习的三维模型检索算法研究
  4. 在linux中 如何创建磁盘配额,如何在Linux系统中配置磁盘配额?
  5. python的os库_os库(python)—总结
  6. thinkphp5 mysql助手_ThinkPHP5-数据库基本操作
  7. 一个简单的EJB-Session Bean实例
  8. 什么是jQuery?
  9. 前端chrome浏览器调试总结??
  10. 大数据学习笔记:创建与配置虚拟机[Ubuntu + CentOS]