天天看點

Spring 最佳實踐 - Spring提供的遠端通路(二)

8.2HTTP調用

RMI雖然是Java标準的遠端調用模式,但是RMI最大的特點是使用特定的JRMP(Java Remote MethodProtocol,Java 遠端方法協定) 二進制協定,很難穿透防火牆,僅适合企業内容網絡中使用。如果需要跨防火牆調用,則HTTP協定幾乎是唯一的選擇。

是以我們需要一種以HTTP協定為基礎的遠端調用。Spring支援3中基于HTTP協定的遠端調用,以及我們将在下面讨論的WEB服務,在這裡先讨論Spring支援3中HTTP遠端調用。

Hessian 和 Burlap 這兩種基本HTTP的遠端調用協定是有Caucho開發的,并且內建在Resin服務期内,可以直接使用。Hessian是一個二進制協定,而Burlap是一個基于XML的 ,兩者沒有本質的不同。差別在于,Hessian由于使用了二進制協定,是以效率更高,但是很難被讀懂,而Burlap使用XML作為載體,其傳輸内容很容易被開發人員所了解,并且,從理論上講,任何其他語言隻要能解析XML就可以使用Burlap和Java程式通信。不過,這兩種協定由于是私有協定,并沒有成為标準,是以僅适合Java系統内跨防火牆進行調用。

除Hessina和Burlap外,Spring本身還提供了一個HTTP遠端調用協定,我們暫且稱之為HTTP Invoker。和Hessian、Burlap使用自定義的序列化機制有所不同,HTTP Invoker使用Java标磚的序列化機制,通過HTTP協定來實作遠端調用,是以這種方式也适用于Java應用程式的通信。

在Spring中,使用Hessian、Burlap和HTTP Invoker非常容易,我們甚至根本無需了解其API細節就可以直接使用它們。下面的HttpCall_Server工程示範了在Spring環境下将服務接口暴露成為遠端服務的方法。由于Hessian、Burlap和HTTP Invoker都需要通過Servlet來實作服務接口,是以,該工程是一個基于Spring MVC架構的WEB應用程式。

我們設定了一個非常簡單的接口TimeService,用于傳回目前時間。

public interface TimeService {

     String getTime();  

}

TimeServiceImpl是實作類,其實作非常簡單。

public class TimeServiceImpl implements TimeService {

@Override

    public String getTime() {

       return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());

    }

}

現在,我們需要将TimeService 暴露為遠端接口,以便用戶端可以通過HTTP實作遠端調用。在Spring中,通過Hessian、Burlap和HTTP Invoker實作該服務非常簡單,Spring已經提供了現成的HttpRequestHandler,隻需要告訴Spring業務接口和實作類,就立刻可以将其輸出為遠端接口。在Spring的XML配置檔案dispatcher-servlet.xml中定義如下:

<beanid="timeService"class="com.zsw.httpcall.TimeServiceImpl"/>

<beanname="/HessianService"class="org.springframework.remoting.caucho.HessianServiceExporter">

<propertyname="service"ref="timeService"/>

<propertyname="serviceInterface"value="com.zsw.httpcall.TimeService"/>

</bean>

<beanname="/BurlapService"class="org.springframework.remoting.caucho.BurlapServiceExporter">

<propertyname="service"ref="timeService"/>

<propertyname="serviceInterface"value="com.zsw.httpcall.TimeService"/>

</bean>

<beanname="/SpringHttpService"class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">

<propertyname="service"ref="timeService"/>

<propertyname="serviceInterface"value="com.zsw.httpcall.TimeService"/>

</bean>

以Hessian為例,隻需首先定義好提供服務的TimeService Bean,然後将TimeService接口及其實作類注入到HessianServiceExporter,就立刻實作了一個Hessian遠端調用服務。Burlap和HTTP Invoker的配置完全相同。我們甚至在編譯器沒有用到任何額外的jar包實作了3個遠端調用接口。

下一步需要在WEB.xml中配置好Spring的DispatchServlet。

<servlet>

<servlet-name>dispatcher</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>0</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>dispatcher</servlet-name>

<url-pattern>/remote/*</url-pattern>

</servlet-mapping>

下一步,我們需要編寫用戶端來實作遠端調用上述服務。在Eclipse中建立一個HttpCall_Client工程,結構如下:

Spring 最佳實踐 - Spring提供的遠端通路(二)

在Spring中調用Hessian、Burlap和HTTP Invoker也非常容易。首先,将TimeService接口從HttpCall_Server工程中複制過來,然後再config.xml中配置如下:

<beanid="hessianService"class="org.springframework.remoting.caucho.HessianProxyFactoryBean">

<propertyname="serviceUrl"value="http://localhost:8080/remote/HessianService"/>

<propertyname="serviceInterface"value="com.zsw.httpcall.TimeService"/>

</bean>

<beanid="burlapService"class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">

<propertyname="serviceUrl"value="http://localhost:8080/remote/BurlapService"/>

<propertyname="serviceInterface"value="com.zsw.httpcall.TimeService"/>

</bean>

<beanid="springHttpService"class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">

<propertyname="serviceUrl"value="http://localhost:8080/remote/SpringHttpService"/>

<propertyname="serviceInterface"value="com.zsw.httpcall.TimeService"/>

</bean>

以Hesian為例,為了獲得遠端接口,隻需要将服務端位址和接口類注入到HessianProxyFactoryBean中,其傳回的即時具有TimerService接口的遠端對象,用戶端隻需要調用該對象即可,甚至不知道該對象到底是否是一個遠端對象。Burlap和HTTP Invoker的配置和Hessian完全相同。

為了讓讀者更直覺地看到遠端調用的效果,我們做出了一個Swing界面,允許使用者選擇使用哪個遠端對象。先啟動HttpCall_Server工程,然後運作HttpCall_Client的Main方法,效果如下:

Spring 最佳實踐 - Spring提供的遠端通路(二)

以上3中HTTP調用都可以跨防火牆,不過,由于使用的都是私有協定,是以隻能用于Java應用程式之間的遠端調用。如果希望和易購平台實作遠端調用,就不洗使用标磚的WEB服務 (Web Services).