配置文件是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;  }  }  

转载于:https://www.cnblogs.com/wade-luffy/p/6086486.html

SpringRMI解析2-RmiServiceExporter逻辑脉络相关推荐

  1. SpringRMI解析3-RmiServiceExporter逻辑细节

    在发布RMI服务的流程中,有几个步骤可能是我们比较关心的. 获取registry 由于底层的封装,获取Registry实例是非常简单的,只需要使用一个函数LocateRegistry.createRe ...

  2. 全面解析并实现逻辑回归(Python)

    本文以模型.学习目标.优化算法的角度解析逻辑回归(LR)模型,并以Python从头实现LR训练及预测. 一.逻辑回归模型结构 逻辑回归是一种广义线性的分类模型且其模型结构可以视为单层的神经网络,由一层 ...

  3. 结果集 tostring_关于避免对toString()结果进行解析或基于逻辑的美德

    结果集 tostring 使用Java或我使用过的其他编程语言,我发现有时候可以用该语言完成某些事情,但通常不应该这样做. 通常,这些误用语言似乎无害,当开发人员首次使用它们时可能是有益的,但后来同一 ...

  4. 关于避免对toString()结果进行解析或基于逻辑的美德

    使用Java或我使用过的其他编程语言,我发现有时可以用该语言完成某些事情,但通常不应该这样做. 通常,这些误用语言似乎无害,当开发人员首次使用它们时可能有益,但后来同一位开发人员或另一位开发人员遇到了 ...

  5. 解析全球人工智能核心脉络——北京智源大会2周倒计时

    报名请点击「阅读原文」 -北京·国家会议中心- 2019年10月31日-11月1日 www.baai.ac.cn/2019 BAAI 距离北京智源大会(BAAI Conference) 只有两周啦!智 ...

  6. mysql逻辑读高影响_运维日记| MySQL/Oracle深度解析之一:逻辑读

    前言 THE FIRST 比较数据库优劣.异同的文章有很多了,使用压测工具,进行不同压力下的测试,就能大致上比较出来哪种数据库是"最快"的数据库.但从有经验的数据架构.DBA等专业 ...

  7. 复盘49个硬币资本投资项目,8大维度解析其投资逻辑与布局

    在目前阶段,与其定论区块链是一次生产关系革命,不如实事求是认清区块链仍处在初步实验阶段,各项基础设施仍未建成,具有良好体验的产品尚未出现.在接下来的一段时间,会有大批项目集中落地,这些一代项目的进展对 ...

  8. mysql 慢日志 逻辑读_运维日记| MySQLOracle深度解析之一:逻辑读

    前言 THE FIRST 比较数据库优劣.异同的文章有很多了,使用压测工具,进行不同压力下的测试,就能大致上比较出来哪种数据库是"最快"的数据库.但从有经验的数据架构.DBA等专业 ...

  9. oracle运维与mysql_运维日记| MySQL/Oracle深度解析之一:逻辑读

    前言 THE FIRST 比较数据库优劣.异同的文章有很多了,使用压测工具,进行不同压力下的测试,就能大致上比较出来哪种数据库是"最快"的数据库.但从有经验的数据架构.DBA等专业 ...

  10. mysql hash函数_运维日记| MySQL/Oracle深度解析之一:逻辑读

    前言 THE FIRST 比较数据库优劣.异同的文章有很多了,使用压测工具,进行不同压力下的测试,就能大致上比较出来哪种数据库是"最快"的数据库.但从有经验的数据架构.DBA等专业 ...

最新文章

  1. winform解析json
  2. 中国数字化进程比发达国家快,小程序让我感到自豪 | IT领袖峰会
  3. C++(二)——命名空间(上)
  4. 160个Crackme023
  5. 牛客网 在线编程 折纸问题
  6. 最优化5-8章重点(考试点全)
  7. python selenium api_Selenium2+python自动化-查看selenium API
  8. e的矩阵次方_利用状态转移矩阵和VBA求游戏中各种事件达成次数的期望
  9. 奇讯新游 PHP,QXPLAY
  10. 深度学习最全优化方法总结比较(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)(转)...
  11. Java学习笔记分享之Dubbo篇
  12. Cypress系列(21)- 可操作类型的命令 之 check()、uncheck()
  13. 丹佛大学计算机专业,丹佛大学计算机工程排名第81(2018年TFE美国排名)
  14. 迅雷,快车,旋风下载地址加密和解密分析
  15. GEE学习笔记 七十七:GEE学习方法简介
  16. 性能优化,进无止境---CPU篇
  17. 常用的RGB颜色值参考表
  18. 微信小程序—半圆(弧形)进度条
  19. 字符串切割函数strtok、strtok_s、strtok_r的区别
  20. 清除浏览器默认表单边框/背景特效和下拉菜单背景

热门文章

  1. TP5整合的阿里云短信接口
  2. 在lamp上简单部署应用程序
  3. 单位转换及格式化显示
  4. 了解typename的双重意义
  5. Dojo 1.7正式发布
  6. MyEclipse 保护色设置
  7. ES6的promise对象应该这样用
  8. MFC 简单输出EXCEL - (OLE)
  9. Android开发文摘集合1
  10. hdu 5003 模拟水题 (2014鞍山网赛G题)