« Remoting and web services using Spring | 網頁 | 人工智慧遊戲 - 20Q »

10/06/2005

Remoting and web services using Spring

Spring Framework 具有動態產生 proxy 的功能,也就是,給定一個類別或介面,它可以在執行期,產生此類別或介面的代理物件。這樣做的好處是,我們可以透過代理物件,在呼叫原始物件方法的前後動些手腳:像是權限檢查、日誌、效能檢測、訊息過濾... 乃至我要在這裡介紹的,透過代理物件來存取遠端的物件實體。用途相當多樣化。

傳統的 Client/Server 設計,常會與底層的傳輸協定產生緊密的耦合。例如傳統的 RMI,要採用 RMI 傳輸協定的 Client/Server 系統,其遠端介面必須 extends RMI 的 Remote 介面,而這就產生了系統與協定的耦合。但仔細回想,這樣的耦合卻是不必要的。怎麼說呢?

概念上,我們可以把 Client 跟 Server 兩端看成是河的兩岸。當 Client 端的某一物件要呼叫 Server 端的另一物件時,就像是河的一端派了個特使要過河傳達訊息。而 Client 端與 Server 端的傳輸協定,就像是兩者間的各種運輸管道。例如水泥橋、吊橋,或是般隻。事實上,河的兩岸可以是個獨立的個體,特使要過河,他可以走水泥橋、吊橋,或是搭乘般隻。從這個角度來思考,實在沒有必要把 Client/Server 架構跟底層的傳輸協定綁在一塊。

Spring 在遠端呼叫上,支援多種協定,包括傳統的 RMI、能穿越防火牆的 HTTP Object Stream,以及跨系統的 Web Service。由於 proxy 物件是動態產生的,並不需要事先編譯,因此甚至能做到動態變更底層的傳輸協定 (也就是解了系統與傳輸協定的耦合),而不用變更一行的程式碼。究竟 Spring 是怎麼辦到的呢?

答案很簡單,其實說穿了就是嚴格區分物件的角色(有沒有注意到這裡也有 AOP 的影子)。執行商業邏輯的物件,就不該管如何將其服務開放出來(這也就是讓 Business service 去 extends RMI Remote 介面不好的原因)。在 Spring 裡面,把 export service 的動作,交給 ServiceExporter 來處理。今天你想讓 AccountService 經由 RMI 呼叫,那就把它交由 RmiServiceExporter export 吧!若是想讓它經由 HTTP 呼叫,那就交由 HttpInvokerServiceExporter export 吧!其他的協定亦然。從 Server 端的角度來講,經由不同的 exporter,就可以支援各式各樣的呼叫介面了。

反觀 Client 端,也可能會面對採用不同傳輸協定的 Server。這時 Client 端見人說人話,見鬼說鬼話的能力就很重要了。在 Spring 裡面,提供了許多的 ProxyFactoryBean。採用不同的 ProxyFactoryBean,就能讓你連到不同協定的 Server,而不用改寫一行 Client 端程式。

詳細的範例,我就不在此列舉了,有興趣的請移駕前往 Spring 使用手冊第 17 章:Remoting and web services using Spring

發表留言