RMI远程服务创建流程分析
1、远程对象创建过程
首先步入对象的构造方法
下一步
这里步入了父类UnicastRemoteObject的构造函数,传入一个参数port
,作用是将远程对象随即发布到一个端口,此时默认值为0
这里对端口以及相关属性初始化,主要关注构造方法中的exportObject
方法,将远程对象转换为Remote类型,与port端口传入方法中。两个被赋值null的参数与RMI获取客户端或服务端套接字有关。
进入exportObject
方法
返回值的两个参数,第一个参数obj为创建的远程对象,第二个参数中新建了一个UnicastServerRef
对象,并传入了端口port
继续跟进第二个参数
UnicastServerRef
构造函数中调用父类构造器,创建一个LiveRef
对象作为参数。var1=port
跟进LiveRef
ObjID应该与UID相关,目前不深究,继续跟进构造方法
到此已经可以看到与网络通信相关的类了,跟进TCPEndpoint
,在跟进getLocalEndpoint方法之前,先来看看这个类的构造函数
发现了host和port属性被赋值了,就是在这个构造函数中,确定了远程对象的主机与端口
再来看getLocalEndpoint
方法
后两个参数与RMI获取套接字有关,由于传入的值为null,不做分析
最终返回一个192.168.56.1:0的 地址:端口
回到LiveRef
构造方法
可以知道通过第二个参数获取了远程对象需要的地址与端口,继续跟进LiveRef
方法
this.ep
被赋值为Endpoint,与远程对象的地址端口有关。
重点看一下ep
其中包括了host
与port
,以及一个非常重要的transport
对象,transport
才是真正处理网络请求的对象,TCPEndpoint
是一层封装。
赋值完成后继续跟进,会回到UnicastServerRef
调用父类构造器的地方。
父类构造器只是对ref属性赋值为创建的LiveRef
对象
到这里,说明一下UnicastServerRef
与UnicastRef
的关系
UnicastRef是UnicastServerRef的父类,UnicastServerRef继承UnicastRef使用于服务端,后者直接使用于客户端。
继续跟进回到exportObject
方法
到目前为止,创建的LiveRef对象已经包含在sref中,并将sref赋值给远程对象obj的ref中。到此远程对象与需要的地址,端口等信息已经成功绑定。
继续跟进sref.exportObject
在这个方法中,为远程对象创建了一个代理,也就是客户端需要调用时使用的stub
,在后续创建注册表后,将远程对象的stub
放到注册中心,后续客户端从注册表获取stub
进行远程调用。
跟进createProxy
当前的if
判断,若进入会创建stub
,条件主要根据stubClassExists
值判断
可以看到stubClassExists
中检测类名是否以_Stub
结尾,这里主要在注册表相关操作中生效,如jar包中已经写好的类
不进入if
语句中,之后进入动态代理的创建流程
获取类加载器,获取远程接口,获取调用处理器,使用三个参数创建代理
类加载器为AppClassLoader
远程接口中包含了远程对象接口RemoteObj
等信息
处理器本质上还是LiveRef
的封装
回到exportObject
中
这个判断创建的stub
是否是RemoteStub
的实例,这里判否,跳过
跟进Target
构造方法
最重要的两个属性是disp
和stub
,具体看看他们封装的内容
disp
是UnicastServerRef
类型,而stub
代理中的ref
是UnicastRef
类型,而stub
是需要发布到注册表中,提供客户端获取使用的,其中都封装了同一个LiveRef
,这也是RMI
进行通信的核心,即使用LiveRef
提供服务端和客户端使用。
其中还有一个比较重要的属性weakImpl
这里包含了接口的具体实现。
创建好Target后,执行ref.exportObject
跟进该方法
listen
方法,这个是开启网络监听的方法。跟进listen
主要看newServerSocket
方法,这个方法创建了用于监听的socket
。
继续跟进
端口是通过createServerSocket
方法修改的,继续跟进
在ServerSocket
中,若将端口设为0,操作系统会为服务器自动分配一个端口,远程对象的端口在这个位置被修改了,listen
根据host
和port
创建监听。
到此服务端远程对象的创建已经结束。接下来还需要在服务端对发布的对象进行记录。
调用ObjectTable.putTarget
方法,其中有两个put
方法。
var0
为创建的Target
对象,使用put
方法将target
的信息保存在系统的两个表中,到此服务端远程对象创建流程介绍完毕。
总结一下,在服务端创建远程对象过程中,核心为LiveRef
,LiveRef
对象中包含了远程对象占用的地址和端口,以及对象UID。当一个远程对象被创建时,会生成一个服务器本地的RemoteObject
对象,它持有一个UnicastServerRef
对象,UnicastServerRef
对象持有一个LiveRef
对象;远程对象被创建时,还会生成一个UnicastRef
对象,并封装到stub
代理中,它持有与UnicastServerRef
相同的LiveRef
,stub
后续发布到注册表,以供客户端使用。