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。