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

简介:

接上:http://guojuanjun.blog.51cto.com/277646/1423392

这一次我们从学习RegistryImpl_Stub.java和RegistryImpl_Skel.java的实现上学习远程方法的调用过程。

wKiom1OS6YWzqCXTAACwnhazzLE239.jpg

RegistryImpl_Stub.bind:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public  void  bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
     throws  java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException
     {
     try  {
         if  (useNewInvoke) {
         ref.invoke( this , $method_bind_0,  new  java.lang.Object[] {$param_String_1, $param_Remote_2}, 7583982177005850366L);
         else  {
         java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)  this , operations,  0 , interfaceHash);
         try  {
             java.io.ObjectOutput out = call.getOutputStream();
             out.writeObject($param_String_1);
             out.writeObject($param_Remote_2);
         catch  (java.io.IOException e) {
             throw  new  java.rmi.MarshalException( "error marshalling arguments" , e);
         }
         ref.invoke(call);
         ref.done(call);
         }
     catch  (java.lang.RuntimeException e) {
         throw  e;
     catch  (java.rmi.RemoteException e) {
         throw  e;
     catch  (java.rmi.AlreadyBoundException e) {
         throw  e;
     catch  (java.lang.Exception e) {
         throw  new  java.rmi.UnexpectedException( "undeclared checked exception" , e);
     }
     }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  public  StreamRemoteCall(Connection c, ObjID id,  int  op,  long  hash)
         throws  RemoteException
     {
         try  {
             conn = c;
             Transport.transportLog.log(Log.VERBOSE,
                 "write remote call header..." );
 
             // write out remote call header info...
             // call header, part 1 (read by Transport)
             conn.getOutputStream().write(TransportConstants.Call);
             getOutputStream();            // creates a MarshalOutputStream
             id.write(out);                // object id (target of call)
             // call header, part 2 (read by Dispatcher)
             out.writeInt(op);             // method number (operation index)
             out.writeLong(hash);          // stub/skeleton hash
         catch  (IOException e) {
             throw  new  MarshalException( "Error marshaling call header" , e);
         }
     }

只要传入对象ID,操作号,接口hash值,就可以定位到远程对象及其方法上。

再看服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  
     public  boolean  serviceCall( final  RemoteCall call) {
         try  {
             
             final  Remote impl;
             ObjID id;
 
             try  {
                 id = ObjID.read(call.getInputStream());
             catch  (java.io.IOException e) {
                 throw  new  MarshalException( "unable to read objID" , e);
             }
 
             /* get the remote object */
             Transport transport = id.equals(dgcID) ? null : this;
             Target target =
                 ObjectTable.getTarget(new ObjectEndpoint(id, transport));
 
             if (target == null || (impl = target.getImpl()) == null) {
                 throw new NoSuchObjectException("no such object in table");
             }
 
             final Dispatcher disp = target.getDispatcher();
             target.incrementCallCount();
             try {
                 /* call the dispatcher */
                 transportLog.log(Log.VERBOSE, "call dispatcher");
 
                 final AccessControlContext acc =
                     target.getAccessControlContext();
                 ClassLoader ccl = target.getContextClassLoader();
 
                 Thread t = Thread.currentThread();
                 ClassLoader savedCcl = t.getContextClassLoader();
 
                 try {
                     t.setContextClassLoader(ccl);
                     currentTransport.set(this);
                     try {
                         java.security.AccessController.doPrivileged(
                             new java.security.PrivilegedExceptionAction<Void>() {
                             public Void run() throws IOException {
                                 checkAcceptPermission(acc);
                                 disp.dispatch(impl, call);
                                 return null;
                             }
                         }, acc);
                     } catch (java.security.PrivilegedActionException pae) {
                         throw (IOException) pae.getException();
                     }
                 } finally {
                     t.setContextClassLoader(savedCcl);
                     currentTransport.set(null);
                 }
 
             } catch (IOException ex) {
                 transportLog.log(Log.BRIEF,
                                  "exception thrown by dispatcher: ", ex);
                 return false;
             } finally {
                 target.decrementCallCount();
             }
 
         } catch (RemoteException e) {
 
             // if calls are being logged, write out exception
             if (UnicastServerRef.callLog.isLoggable(Log.BRIEF)) {
                 // include client host name if possible
                 String clientHost = "";
                 try {
                     clientHost = "[" +
                         RemoteServer.getClientHost() + "] ";
                 } catch (ServerNotActiveException ex) {
                 }
                 String message = clientHost + "exception: ";
                 UnicastServerRef.callLog.log(Log.BRIEF, message, e);
             }
 
             /* We will get a RemoteException if either a) the objID is
              * not readable, b) the target is not in the object table, or
              * c) the object is in the midst of being unexported (note:
              * NoSuchObjectException is thrown by the incrementCallCount
              * method if the object is being unexported).  Here it is
              * relatively safe to marshal an exception to the client
              * since the client will not have seen a return value yet.
              */
             try  {
                 ObjectOutput out = call.getResultStream( false );
                 UnicastServerRef.clearStackTraces(e);
                 out.writeObject(e);
                 call.releaseOutputStream();
 
             catch  (IOException ie) {
                 transportLog.log(Log.BRIEF,
                     "exception thrown marshalling exception: " , ie);
                 return  false ;
             }
         }
 
         return  true ;
     }
1
  id = ObjID.read(call.getInputStream());

读到ObjId.

1
2
3
Target target =
                 ObjectTable.getTarget( new  ObjectEndpoint(id, transport));
impl = target.getImpl()

从对象表中找到远程对象的target对象,并获取远程对象。

1
  disp.dispatch(impl, call);

分发调用到远程对象上。

 RegistryImpl的远程调用是这样实现,但普通对象在JDK1.5之后,已没有显示的stub类.而是用一个代理类代替存根对象,具体参考:http://guojuanjun.blog.51cto.com/277646/1350826



本文转自 anranran 51CTO博客,原文链接:http://blog.51cto.com/guojuanjun/1423511

相关文章
|
11月前
|
存储 分布式计算 Java
JavaRMI配置详解 实现远程方法调用
JavaRMI(Java Remote Method Invocation)是Java语言提供的一种远程方法调用的技术。通过JavaRMI,开发人员可以在不同的Java虚拟机(JVM)之间进行远程方法调用,实现分布式计算和通信。本文将详细介绍JavaRMI的配置,以及如何实现远程方法调用。
188 0
|
网络安全 SDN Docker
Docker是怎么实现网络通信的?底层原理是什么?
Docker是怎么实现网络通信的?底层原理是什么?
220 0
|
Dubbo Java 应用服务中间件
java远程调用之RMI(终于可以自己写代码控制别人电脑了)
之前在研究生课程当中学了分布式系统这门课,而且还是自己的导师讲的这门课,在课堂上迷迷糊糊的晃悠了一学期,除了听见几个名词,也没太多印象。正好这几天用到远程过程调用,使用的是gRPC,想到之前上课听过,于是把这块的知识从书到教程好好地补充了一下。 本篇文章尽量不啰嗦,它的重要性自己可以私下了解一下。
321 0
java远程调用之RMI(终于可以自己写代码控制别人电脑了)
|
Dubbo 前端开发 网络协议
一文告诉你 Java RMI 和 RPC 的区别!
RPC(Remote Procedure Call Protocol)远程过程调用协议,通过网络从远程计算机上请求调用某种服务。
一文告诉你 Java RMI 和 RPC 的区别!
|
Dubbo Java 应用服务中间件