1. Spring Remote Service Overview
RPC调用类似于调用本地对象的方法,都是同步的操作,调用代码将被阻塞,直到被调用过程完成为止。
本地调用就是execute process在同一个应用的两个代码块中交换。RPC就是execute process从一个应用通过网络传递给另外一个应用。
Spring Remote Service支持这几种模式:RMI, Hessian, Burlap, HTTP invoker和JAX-RPC。
在Server端,Spring可以通过相应的RemoteExporter将一个Bean的发布成一个remote service。
2. RMI in Spring
使用RMI服务
使用RmiProxyFactoryBean来创建一个指向RMI服务的proxy。
1 | <bean id="myRemoteService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> |
3 | <property name="serviceUrl" values="rmi://${host}/MyRemoteService"> |
5 | <property name="serviceInterface" values="xxx.MyRemoteService"> |
然后spring中其余的bean如果想使用这个remote service的话,只需要使用注入机制将myRemoteService注入到需要的地方即可。不必关心这服务从哪里来甚至不需要知道这是个remote service。
传统方法创建一个RMI服务:
- Service实现类,并且方法要抛出RemoteException。
- 编写Service接口,继承Remote。
- 通过rmic创建stub(客户端)和skeleton(服务器端)
- 启动一个rmi registry,并注册。
Spring中创建RMI服务
编写Service接口,但不需要继承Remote,所有方法都不需要抛出RemoteException。
1 | public interface MyRemoteService { |
3 | String getResponseFromServer(String input); |
编写Service实现类
1 | public class MyRemoteServiceImpl implements MyRemoteService{ |
3 | public String getResponseFromServer(String input){ |
5 | return "input:" + input + ", response: hello"; |
将MyRemoteServiceImpl配置为一个bean
1 | <bean id="myRemoteService" class="xxx.MyRemoteServiceImpl"> |
使用RmiServiceExporter将MyRemoteServiceImpl发布成RMI服务
01 | <bean class="org.springframework.remoting.rmi.RmiServiceExporter"> |
03 | <property name="service" ref="myRemoteService"> |
05 | <property name="serviceName" value="MyRemoteService"> |
07 | <property name="serviceInterface" value="xxx.MyRemoteService"> |
09 | <property name="registryHost" value="aaronfu.net"> |
11 | <property name="registryPort" value="1099"> |
RMI缺点:RMI在有防火墙的环境下运行会有困难,而且RMI要求客户端和服务器端都必须用Java编写。
3. Hessian和Burlap
Hession和Burlap都是Caucho Technology的框架,基于HTTP的轻量级remote service。
Hessian使用binary消息来建立客户端和服务器端之间的交流,因为基于binary所以对通迅带宽的占用小。所以不依赖于语言可以被Java之外的语言所用。
Burlap是基于XML的技术,消息可读性比较好,而且Burlap相比其他基于XML的技术比如SOAP来说,Burlap的消息结构比较简单,不需要WSDL之类的东西额外定义。
使用Hessian(客户端代码)
和RMI类似,Spring使用HessianProxyFactoryBean来创建一个指向Hessian服务的proxy。
01 | <bean id="myHessianRemoteService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"><property name="serviceUrl"><value>http://${serverName}/${contextPath}/myHessian.service</value> |
05 | <property name="serviceInterface"> |
07 | <value>xxx.MyRemoteService</value> |
使用Burlap(客户端代码)
相同的配置也适用于Burlap,仅仅是变成使用BurlapProxyFactoryBean
01 | <bean id="myHessianService" class="org.springframework.remoting.caucho.BurlapProxyFactoryBean"><property name="serviceUrl"> |
03 | <value>http://${serverName}/${contextPath}/myHessian.service</value> |
07 | <property name="serviceInterface"> |
09 | <value>xxx.MyRemoteService</value> |
由此可见,当使用Spring时,可以很简单的在各种Spring所支持的remote技术之间切换,而仅仅需要更改很少的配置。
输出Hessian服务
将POJO的public方法公开成Hessian服务。HessianServiceExporter是一个Spring MVC controller,接收Hessian的请求然后翻译成对POJO的方法调用。
01 | <bean id="myHessianRemoteService" class="org.springframework.remoting.caucho.HessianServiceExporter"> |
03 | <property name="service"> |
05 | <ref bean="myHessianService"/> |
09 | <property name="serviceInterface"> |
11 | <value>xxx.MyRemoteService</value> |
Hessian不需要注册,所以没必要像RMI那样设置serviceName属性。
在Spring中配置一个URL handler,用来将URL匹配给指定的Hessian Service Bean
01 | <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">< |
02 | property name="mappings"> |
06 | <prop key="/myHessian.service">myHessianRemoteService</prop> |
12 | <property name="serviceInterface"> |
14 | <value>xxx.MyRemoteService</value> |
- 为HessianServiceExporter配置DispatcherServlet
因为HessianServiceExporter是Spring MVC中的一个controller实现,我们需要在web.xml中配置DispatcherServlet:
1 | <servlet><servlet-name>myHessian</servlet-name> |
3 | <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> |
5 | <load-on-startup>1</load-on-startup> |
1 | <servlet-mapping><servlet-name>myHessian</servlet-name> |
3 | <url-pattern>*.service</url-pattern> |
输出Burlap服务
Burlap服务的输出几乎和Hessian是一样的,不同的地方就是使用org.springframework.remoting.caucho.BurlapServiceExporter。也需要为它配置URL handler和DispatcherServlet。
4. HTTP invoker
RMI使用Java标准的序列化机制,但是很难穿过防火墙;Hessian/Burlap能穿越防火墙但是使用自己私有的一套系列化机制。
因此HTTP invoker应运而生,使用HTTP协议能通过防火墙,并且使用Java序列化机制。
使用HTTP invoker
和RMI,Hessian等相同,HTTP invoker也是通过HttpInvokerProxyFactoryBean。
输出HTTP invoker服务
和Hessian相同,不同的地方就是使用org.springframework.remoting.httpinvoder.HttpInvokerServiceExporter。也需要为它配置URL handler和DispatcherServlet。
HTTP invoder的限制就是客户端和服务器端必须使用Spring。