第33章 Spring远程方案(二)

第33章 Spring远程方案

33.3 Spring Remoting提供的远程服务支持

33.3.2 基于HTTP的轻量级Remoting方案

SpringRemoting提供了三种基于HTTP的远程方案:

  • Spring框架自行开发的HttpInvoker方案;

  • 基于Caucho的Hessian远程方案;

  • 基于Caucho的Burlap远程方案。

在进一步了解每一种方案之前,我们先来从总体上分析一下,这些基于HTTP的轻量级远程方案都有哪些共通之处,或者说它们是怎么实现的。

1. 基于HTTP远程方案的实现原型分析

实际上要理解基于HTTP的远程方案是如何实现的并不困难,即使你之前没有开发过任何Web应用程序,一旦完成了Spring MVC之旅,我就可以十分肯定地告诉你,你实际上已经使用基于HTTP的远程方案很久了!难道你通过浏览器这种特定的客户端所请求的,不就是远程的服务器上的各种服务吗?

要将一个本地服务以HTTP的方式公开给远程客户端使用(当然,并不仅限于浏览器),最简单的办法就是为其提供一个Servlet实现,让该Servlet统一接收客户端调用请求,然后根据请求调用本地的服务对象,并最终将调用结果返回给相应的客户端。不过,要为每个服务对象都提供一个Servlet实现显然有些冗余了,而且,我们通常也无法在Servlet中直接获取到Spring的IoC容器的各种服务。鉴于SpringMVC已经有现成的DispatcherServlet可用的情况下,要公开相应的服务对象,实际上只需要提供相应的Controller即可。哦,确切地讲,是Handler。因为Spring Remoting为各种基于HTTP的远程方案所提供的Service Exporter实现,实际上都属于另一种类型的Handler,即HttpRequestHandler。该接口定义如下:

publicinterfaceHttpRequestHandler {
    
    
  void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException;
}

现在,我们完全可以想象出,Spring Remoting到底是如何通过各种基于HTTP的轻量级远程方案将相应的服务对象公开出去的。正如下方代码清单中的原型代码所展示的那样。

public class PrototypeServiceExporter implements HttpRequestHandler {
    
    
	private IYourServiceType yourService;
  
	public void handleRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {
    
    
		Object requestData = getMethodNameAndArgumentsOfServiceMethod(request);
		Object result = invokeServiceMethod(yourService, reguestData);
		writeInvocationResultToClient(result, response);
  	}
	// setter方法、getter方法和其他helper方法定义...
}

当把类似的PrototypeServiceExporter添加到DispatcherServlet的上下文之后,如下所示:

<bean name="/yourServiceExposedViaHttp" class="..PrototypeServiceExporter">
	<property name="yourService" ref="yourService"/>
</bean>

我们是不是就可以通过如下的URI进行访问了呢?

http://host:port/application/yourServiceExposedViaHttp

当然,现在我们通过该URL发送的请求内容,要变成所调用的远程服务的方法名以及相关的调用参数了。通过HTTP公开远程服务实际上就是这么回事,写写相应的Handler而已。不过,使用Spring Remoting之后,这些Handler都不用我们写,因为Spring Remoting已经提供了现成的实现,如图33-6所示。

image-20220722153448041

我们所要做的,就剩下在使用的时候简单配置一下它们了!

对于相应客户端如何访问各种基于HTTP的远程服务的处理方式,Spring Remoting采用的是ProxyFactoryBean的形式。这样做的好处我们已经了解了,相应的ProxyFactoryBean负责将远程服务接口的代理对象注入给客户端,这样,客户端调用方就可以透明的方式访问这些服务。在实现细节上,不用说也能猜得到。当调用方调用远程服务代理对象的相应方法的时候,ProxyFactoryBean挂钩的MethoaInterceptor就可以对调用进行拦截,然后将拦截到的方法调用信息编组发送到服务端。至于将请求数据序列化并发送的功能实现,这就有点儿“八仙过海,各显神通”的味道了。虽然请求的数据内容基本相同,基本上都是要调用的方法名和相应方法参数,但因为各家所采用的数据序列化机制不同,在发送这些请求数据的时候,就得区别对待。对于HTTPInvoker来说,它采用的是标准的Java序列化机制,所以,我们可以通过数据流将请求数据发送给服务器端。而对于Hessian和Burlap来讲,因为数据的发送和编组已经有相应的类负责了,比如对应Hessian的HessianProxyFactory,SpringRemoting的ServiceAccessor实现只是借用一些这些现成的实现类来发送请求数据而已。

基本上,基于HTTP的远程方案只有这些内容。下面让我们从理论转入实践部分,看一下具体使用相应的HTTP远程方案是如何操作的吧!

2. Spring HTTP Invoker

Spring的HTTP Invoker采用标准的Java序列化机制。这与基于RMI的远程方式相同,如果你使用RMI过程中遭受防火墙之类因素的困扰,又不忍舍弃使用功能强大的标准Java数据序列化机制的好处,那么HTTPInvoker或许应该成为你考虑的对象。

要通过HTTPInvoker机制公开一个本地服务,我们使用org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter。但是既然它是一个HttpRequestHandler,要想让它开始工作,我们首先需要将它挂接到某个DispatcherServlet上。如果你有现成的Spring MVC应用所使用的DispatcherServlet,那么,使用现成的也可以。不过,重新设立一个DispatcherServlet专门负责HTTP形式的远程调用,或许能让整个应用看起来更“整齐”一些。所以,我们不妨在现有Web应用的配置文件web.xml中,新添加一个DispatcherServlet用于远程调用(见下方代码清单)。

# web.xml
...
<servlet>
	<servlet-name>remoting</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServ1et</servlet-class>
	<load-on-startup>4</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>remoting</servlet-name>
	<url-pattern>/remoting/*</url~pattern>
</servlet-mapping>
...

有了它之后,我们就可以将ITTMRateService对应的HttpInvokerServiceExporter添加到该DispatcherServlet对应的ApplicationContext中,如下代码所示:

# remoting-gervlet.xml
<bean name="/ttmServiceViaHttpInvoker" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
  <property name="serviceInterface" value="..ITTMRateService"/>
  <property name="service" ref="ttmRateService"/>
</bean>

假设我们已经将ITTMRateService的实现类添加到了Web应用的顶层ApplicationContext中。在这些全部完备之后,相应的远程调用客户端应该可以从http://host:port/application/remoting/tmServiceViaHttpInvoker访问到我们通过HTTPInvoker公开出去的ITTMRateService服务。

说到调用客户端如何访问已经通过HTTPInvoker远程公开出来的ITTMRateService服务,那就更简单了。还记得我们的TTMServiceClient吗?它可是依赖于ITTMRateService接口。显然,我们只要为其注入使用HTTPInvoker进行远程访问的ITTMRateService类型代理对象就可以了,而HttpInvokerProxyFactoryBean就是做这个工作的。下方代码清单给出的正是HttpInvokerProxyFactoryBean的使用配置示例。

# cllent.xml
<bean id="ttmServiceViaHttpInvoker" class="org.springframework.remoti.ng.httpinvoker.HttpInvokerProxyFactoryBean">
	<property name="serviceUrl" value="http://yourhost:8080/application/remoting/ttmServiceViaHttpInvoker"/>
	<property name="serviceInterface" value="..ITTMRateService"/>
</bean>

<bean id="client" c1ass="..TIMServiceClient">
	<property name="ttmService" ref="ttmServiceViaHttpInvoker"/>
</bean>

显然,是使用RMI还是HTTPInvoker进行远程访问,对于我们的TMServiceClient来说,完全没有太大的影响。最终决定使用什么机制来访问远程公开的某个服务,唯一要做的,也就是为其提供Spring Remoting已经实现的各种不同的ProxyFactoryBean型的ServiceAccessor而已。

3. CauchoHession和Burlap

Hessian和Burlap分别采用二进制形式和XML文本形式进行数据传输过程中的序列化,而非采用标准的Java序列化机制。不过,这并不妨害二者的优秀表现。实际上,Caucho已经为我们提供了通过Hessian和Burlap公开和访问相应远程服务的支持,但是,在我们使用Spring框架进行开发过程中,这些支持无法获取像依赖注入之类的服务,比如,Hessian和Burlap需要为每一需要公开的服务对象都提供对应的Servlet实现。显然,这些实现是无法获得依赖注入的好处的,所以,Spring Remoting通过DispatcherServlet统一了这片土地。在HessianServiceExporter和BurlapServiceExporter以HttpRequetHandler的身份出现的时候,它们自然获得了Spring框架的各种服务。

使用Hessian和Burlap来公开我们的ITTMRateService给相应远程客户端使用,分别使用HessianServiceExporter和BurlapServiceExporter这两个ServiceExporter实现。与基于HTTPInvoker的远程服务公开类似,如果最初没有DispatcherServlet为我们的HessianServiceExporter和BurlapServiceExporter提供服务支持的话,请先行准备之。在相应的DispatcherServlet就绪之后(我们不妨沿用HTTPInvoker使用的DispatcherServlet),我们只要将HessianServiceExporter和BurlapServiceExporter添加到其ApplicationContext中,即可激活ITTMRateService基于Hessian和Burlap的对外远程服务,如下方代码清单所示。

# remoting-gervlet.xml
<bean name="/ttmServiceViaHessian" class="org.springframework.remoting.caucho.HessianServiceExporter">
	<property name="serviceInterface" value="..ITTMRateService"/>
	<property name="service" ref="ttmRateService"/>
</bean>

<bean name="/ttmServiceViaBurlap" class="org.springframework.remoting.caucho.BurlapServiceExporter">
	<property name="serviceInterface" value="..ITTMRateService"/>
	<property name="service" ref="ttmRateService"/>
</bean>

只要业务对象设计良好,本地调用自然没的说,就是要去远程公开它,现在也只是添加相应的“外围设备”而已。至于对HessianServiceExporter和BurlapServiceExporter公开出来的ITTMRateService服务,我们使用对应的HessianProxyFactoryBean和BurlapProxyFactoryBean对其进行访问。既然TTMServiceClient依赖于远程接口,我们所要做的也只是将HessianProxyFactoryBean和Burlap-ProxyFactoryBean注入给它了,如下方代码清单所示。

# client.xm1
<bean id="ttmServiceViaBurlap" c1ass="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
	<property name="serviceUrl" value="http://yourhost:8080/app1i.cation/remoting/ttmServiceViaBurlap"/>
	<property name="serviceInterface" value="..ITTMRateService"/>
</bean>

<bean id="ttmServiceViaHessian" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
	<property name="serviceUrl" value="http://yourhost:8080/application/remoting/ttmServiceViaHessian"/>
	<property name="serviceInterface" value="..ITTMRateService"/>
</bean>

<bean id="client" class="..TTMServiceClient">
	<property name="ttmService" ref="ttmServiceViaHessian 或者 ttmServiceViaBurlap"/>
</bean>

客户端到底要通过什么样的方式来访问远程服务,看来只是简单的配置更改了。

注意:有关Hessian、Burlap和HttpInvoker的更多特性,比如安全验证之类,也可以通过相应ServiceExporter/Accessor的配置项进行定义。实际需要的时候,不妨直接查阅对应的Javadoc文档,我们就不对这部分内容做过多阐述了。

猜你喜欢

转载自blog.csdn.net/qq_34626094/article/details/125957298
今日推荐