SpringRMI解析2-RmiServiceExporter逻辑脉络
配置文件是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;
        }
    }  
SpringRMI解析2-RmiServiceExporter逻辑脉络的更多相关文章
- SpringRMI解析3-RmiServiceExporter逻辑细节
		
在发布RMI服务的流程中,有几个步骤可能是我们比较关心的. 获取registry 由于底层的封装,获取Registry实例是非常简单的,只需要使用一个函数LocateRegistry.createRe ...
 - SpringMVC解析4-DispatcherServlet逻辑脉络
		
HttpServlet提供了不同的服务方法,它们是doDelete(),doGet(),doOptions(),doPost(),doPut(),和doTrace(),它会根据不同的请求形式将程序引导 ...
 - SpringRMI解析4-客户端实现
		
根据客户端配置文件,锁定入口类为RMIProxyFactoryBean,同样根据类的层次结构查找入口函数. <bean id="rmiServiceProxy" class= ...
 - SpringRMI解析1-使用示例
		
Java远程方法调用,即JavaRMI(JavaRemote Method Invocation),是Java编程语言里一种用于实现远程过程调用的应用程序编程接口.它使客户机上的运行的程序可以调用远程 ...
 - yolo源码解析(1):代码逻辑
		
一. 整体代码逻辑 yolo中源码分为三个部分,\example,\include,以及\src文件夹下都有源代码存在. 结构如下所示 ├── examples │ ├── darknet.c(主程序 ...
 - Spring MVC视图解析器
		
Spring MVC提供的视图解析器使用ViewResolver进行视图解析,实现浏览器中渲染模型.ViewResolver能够解析JSP.Velocity模板.FreeMarker模板和XSLT等多 ...
 - Android(java)学习笔记205:网易新闻RSS客户端应用编写逻辑过程
		
1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,bl ...
 - Spring MVC之视图解析器
		
Spring MVC提供的视图解析器使用ViewResolver进行视图解析,实现浏览器中渲染模型.ViewResolver能够解析JSP.Velocity模板.FreeMarker模板和XSLT等多 ...
 - 开源OSS.Social微信项目解析
		
前言:OSS.Social是个开源的社交网站接口集成项目,当前也有很多其他不错的项目,不过始终没有我想要的那种简单清晰,只能撸起袖子,从头打造一个.当前正在进行的是对微信项目的开发,这里把对接口的整 ...
 
随机推荐
- codevs 3290 华容道(SPFA+bfs)
			
codevs 3290华容道 3290 华容道 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description 小 B 最近迷上了华容道,可是 ...
 - 【编程题目】有 n 个长为 m+1 的字符串,如果某个字符串的最后 m 个字符与某个字符串的前 m 个字符匹配...
			
37.(字符串)有 n 个长为 m+1 的字符串,如果某个字符串的最后 m 个字符与某个字符串的前 m 个字符匹配,则两个字符串可以联接,问这 n 个字符串最多可以连成一个多长的字符串,如果出现循环, ...
 - struts2文件上传和下载
			
1. struts系统中的拦截器介绍 过滤器:javaweb中的服务器组件,主要针对的请求和响应进行拦截. 拦截器:主要针对方法的调用,进行拦截器,当使用代理对象调用某个方法时候 对方法的调用进行拦截 ...
 - 142. Linked List Cycle II
			
题目: Given a linked list, return the node where the cycle begins. If there is no cycle, return null. ...
 - [SQL Server]如何快速查找使用了某个字段的所有存储过程
			
[SQL Server]如何快速查找使用了某个字段的所有存储过程 当一个系统中使用了很多的表,并且存在大量的存储过程,当数据库中的某个表删除了某个字段,那么相应的存储过程也需要改动,但是我 ...
 - ubuntu下deb包的安装方法
			
ubuntu下deb包的安装方法 简介 deb是debian linus的安装格式,跟red hat的rpm非常相似,最基本的安装命令是:dpkg -i file.deb dpkg 是Debian P ...
 - git安装--linux下的安装
			
一般linux自带git版本很旧,会有一定问题,可以先卸载系统自带git: yum remove git下载及安装git: wget https://github.com/git/git/archiv ...
 - python eval和literal_eval
			
eval是python中一个相当智能的函数,把参数当成表达式,进行最大限度的解析, 比如: a = "[[1,2], [3,4], [5,6], [7,8], [9,0]]" b ...
 - 解决eclipse manven项目添加不了maven dependencis
			
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"& ...
 - Java观察者模式(Observer模式)
			
Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循 ...