SpringRMI解析2-RmiServiceExporter逻辑脉络

简介: 配置文件是Spring的核心,在配置文件中我们可以看到,定义了两个bean,其中一个是对接口实现类的发布,而另一个则是对RMI服务的发布,使用org.springframework.remoting.rmi.RmiServiceExporter类进行封装,其中包括了服务类,服务名,服务接口,服务端口等若干属性,因此我们可以断定,此类应该是发布RMI的关键类。

配置文件是Spring的核心,在配置文件中我们可以看到,定义了两个bean,其中一个是对接口实现类的发布,而另一个则是对RMI服务的发布,使用org.springframework.remoting.rmi.RmiServiceExporter类进行封装,其中包括了服务类,服务名,服务接口,服务端口等若干属性,因此我们可以断定,此类应该是发布RMI的关键类。

根据示例,启动Spring中的RMI服务并没有多余的操作,仅仅是开启Spring的环境:读取xml文件,于是我们分析可能是RmiServiceExporter这个类初始化的时候做了某些操作完成了端口的发布功能。我们看下这个类的结构,RmiServiceExporter实现了Spring中几个比较敏感的接口。其中,DisposableBean接口保证在实现该接口的bean销毁时调用其destroy方法,InitializingBean接口则是保证在实现该接口的bean初始化时调用其afterPropertiesSet方法,所以我们推断RmiServiceExporter的初始化函数入口一定在其afterPropertiesSet方法中。经过查看代码,确认afterPropertiesSet为RmiServiceExporter功能的初始化入口。

public class RmiServiceExporter extends RmiBasedExporter  
    implements InitializingBean, DisposableBean 

果然,在afterProperties函数中将实现委托给了prepare,而在prepare方法中我们找到了RMI服务发布的功能实现,同时,我们也大致清楚了RMI服务发布的流程。

(1)验证service

此处的service对应的是配置中类型为RMIServiceExporter的service属性,它是实现类,并不是接口。尽管后期会对RMIServiceExporter做一系列的封装,但是,无论怎么封装,最终还是会将逻辑引向至RMIServiceExporter来处理,所以,在发布之前需要进行验证。

(2)处理用户自定义的SocketFactory属性。

在RMIServiceExporter中提供了4个套接字工厂配置,分别是clientSocketFactory,serverSocketFactory和registryClientSocketFactory,registryServerSocketFactory。那么这两队配置又有什么区别或者说分别是应用在什么样的不同场景呢?

registryClientSocketFactory于registryServerSocketFactory用于主机与RMI服务器之间连接的创建,也就是当使用LocateRegistry.createRegistry(registryProt,clientSocketFactory,serSocketFactory)方法创建Registry实例时会在RMI主机使用serverSocketFacotry创建套接字等待连接,而服务端RMI主机通信会使用clientSocketFactory创建连接套接字

clientSocketFactory,serverSocketFactory同样是创建套接字,但是使用的位置不同,clientSocketFactory,serverSocketFactory用于导出远程对象,serverSocketFactory用于在服务端建立套接字等待客户端连接,而clientSocketFactory用于调用端建立套接字发起连接

(3)根据配置参数获取Registry

(4)构造对外发布的实例。构建对外发布的实例,当外界通过注册的服务名调用响应的方法时,RMI服务会将请求引入此类来处理。

(5)发布实例

public void afterPropertiesSet() throws RemoteException{  
    prepare();  
}  
public void prepare() throws RemoteException{  
       //检查验证service  
        checkService();  
        if(serviceName == null)  
            throw new IllegalArgumentException("Property 'serviceName' is required");  
        //如果用户在配置文件中配置了clientSocketFactory或者serverSocketFactory的处理  
        //如果配置中的clientSocketFactory同时又实现了RMIServerSocketFactory接口那么会忽略配置 
        //中的serverSocketFactory而使用clientSocketFactory代替 
       if(clientSocketFactory instanceof RMIServerSocketFactory)  
            serverSocketFactory = (RMIServerSocketFactory)clientSocketFactory;  
        //clientSocketFactory和serverSocketFactory要么同时出现,要么都不出现  
       if(clientSocketFactory != null && serverSocketFactory == null || clientSocketFactory == null && serverSocketFactory != null)  
            throw new IllegalArgumentException("Both RMIClientSocketFactory and RMIServerSocketFactory or none required");  
        //如果配置中的registryClientSocketFactory同时实现了RMIServerSocketFactory接口那么会忽略配置张的  
        //registryServerSocketFactory而使用registryClientSocketFactory代替  
       if(registryClientSocketFactory instanceof RMIServerSocketFactory)  
            registryServerSocketFactory = (RMIServerSocketFactory)registryClientSocketFactory;  
        //不允许出现只配置registryServerSocketFactory而不配置registryClientSocketFactory的情况  
       if(registryClientSocketFactory == null && registryServerSocketFactory != null)  
            throw new IllegalArgumentException("RMIServerSocketFactory without RMIClientSocketFactory for registry not supported");  
        createdRegistry = false;  
        //确定RMI registry  
       if(registry == null)  
        {  
            registry = getRegistry(registryHost, registryPort, registryClientSocketFactory, registryServerSocketFactory);  
            createdRegistry = true;  
        }  
        //初始化以及缓存导出的Object  
     //此时通常情况下是使用RMIInvocationWrapper封装的JDK代理类,切面为RemoteInvocationTraceInterceptor  
     exportedObject = getObjectToExport();  
        if(logger.isInfoEnabled())  
            logger.info((new StringBuilder()).append("Binding service '").append(serviceName).append("' to RMI registry: ").append(registry).toString());  
        //Export RMI object  
        if(clientSocketFactory != null)  
            //使用给定的套接字工厂指定的传送方式导出远程对象,以便能够接收传入的调用  
            //clientSocketFactory:进行远程对象调用的客户端套接字工厂  
            //serverSocketFactory:接收远程调用的服务端套接字工厂  
            UnicastRemoteObject.exportObject(exportedObject, servicePort, clientSocketFactory, serverSocketFactory);  
        else  
            //导出remote object,以使它能够接收特定端口的调用  
            UnicastRemoteObject.exportObject(exportedObject, servicePort);  
        try  
        {  
            //绑定服务名称到remote object,外界调用serviceName的时候会被erportObject接收  
            if(replaceExistingBinding)  
                registry.rebind(serviceName, exportedObject);  
            else  
                registry.bind(serviceName, exportedObject);  
        }  
        catch(AlreadyBoundException ex)  
        {  
            unexportObjectSilently();  
            throw new IllegalStateException((new StringBuilder()).append("Already an RMI object bound for name '").append(serviceName).append("': ").append(ex.toString()).toString());  
        }  
        catch(RemoteException ex)  
        {  
            unexportObjectSilently();  
            throw ex;  
        }  
    }  

 

目录
相关文章
|
7月前
|
存储 区块链 数据安全/隐私保护
DApp互助预约排单系统开发设计规则逻辑解析
DApp互助预约排单系统开发设计规则逻辑解析
|
8月前
|
Web App开发 前端开发 JavaScript
Dapp技术开发全解析丨附DAPP源码的逻辑实例解析
智能合约是Dapp的核心组成部分,它是一种基于区块链技术的自动化合约,可以执行预定义的操作和条件。智能合约的执行是去中心化的,可以在区块链上自动执行,无需中间方参与。智能合约的开发需要熟悉Solidity等编程语言,同时需要了解智能合约的安全性问题。
|
3月前
|
编解码 计算机视觉 Python
IPC机制在jetson中实现硬解码视频流数据通信的逻辑解析
IPC机制在jetson中实现硬解码视频流数据通信的逻辑解析
48 0
|
3月前
|
存储 SQL 关系型数据库
drds逻辑表与物理解析
drds逻辑表与物理解析
25 5
|
4月前
|
测试技术 数据库
深入解析MyBatis-Plus中的逻辑删除功能及实例
深入解析MyBatis-Plus中的逻辑删除功能及实例
252 0
|
7月前
|
XML JavaScript 前端开发
SAP UI5 Fiori Elements annotation 的解析逻辑 AnnotationParser.js
SAP UI5 Fiori Elements annotation 的解析逻辑 AnnotationParser.js
40 0
|
7月前
|
XML API 数据格式
SAP UI5 ManagedObject 的 Event 讲解以及 SAP UI5 XML 视图里控件 press 的解析逻辑
SAP UI5 ManagedObject 的 Event 讲解以及 SAP UI5 XML 视图里控件 press 的解析逻辑
45 0
|
8月前
|
JSON 数据格式
通过一个实际例子,讲解 SAP UI5 Compatibility Version 的概念和运行时绑定解析器的选择逻辑
通过一个实际例子,讲解 SAP UI5 Compatibility Version 的概念和运行时绑定解析器的选择逻辑
33 0
|
8月前
|
前端开发 测试技术 API
SAP UI5 Theme Library 的解析逻辑和 SAP UI5 配置元数据的默认值
SAP UI5 Theme Library 的解析逻辑和 SAP UI5 配置元数据的默认值
43 0
|
8月前
|
存储 安全 数据处理
Dapp区块链软件开发丨DAPP源码的逻辑规则解析
DApp 是一种去中心化、开放源码的分布式应用程序。DApp 可以提供多种功能和服务,如智能合约、数字钱包、交易服务、联网身份认证等。DApp 有许多与传统应用程序相似的功能,但其主要特征是去中心化、透明度、程序代码智能、自治性和数据不可篡改性。

推荐镜像

更多