Spring HTTP Invoker一種JAVA遠端方法調用架構實作,原理與JDK的RMI基本一緻,是以我們先跟其它JAVA遠端方法調用實作做下簡單比較。
RMI:使用JRMP協定(基于TCP/IP),不允許穿透防火牆,使用JAVA系列化方式,使用于任何JAVA應用之間互相調用。
Hessian:使用HTTP協定,允許穿透防火牆,使用自己的系列化方式,支援JAVA、C++、.Net等跨語言使用。
Burlap: 與Hessian相同,隻是Hessian使用二進制傳輸,而Burlap使用XML格式傳輸(兩個産品均屬于caucho公司的開源産品)。
Spring HTTP Invoker: 使用HTTP協定,允許穿透防火牆,使用JAVA系列化方式,但僅限于Spring應用之間使用,即調用者與被調用者都必須是使用Spring架構的應用。
為什麼使用Spring HTTP Invoker?我們可以看下Spring源碼中的注釋說明:
1
2
3
4
5
<code>/* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b></code>
<code>* It is more powerful and more extensible than Hessian and Burlap, at the</code>
<code>* expense of being tied to Java. Nevertheless, it is as easy to set up as</code>
<code>* Hessian and Burlap, which is its main advantage compared to RMI.</code>
<code>*/</code>
Spring一定希望大家盡量使用它的産品,但實際項目中我們還是要根據需求來決定選擇哪個架構,下面我們來看看Spring HTTP Invoker的使用。
既然通過是HTTP請求調用,那麼用戶端肯定需要一個代理用于幫忙發送HTTP請求,幫忙做對象系列化和反系列化等,Spring架構中的HttpInvokerServiceExporter類處理這些雜事;而伺服器端需要一個HTTP請求處理器,幫忙處理HTTP請求已經對象系列化和反系列化工作,Spring架構中的HttpInvokerServiceExporter類就是幹這活的,對于Sun JRE 6 的HTTP Server,Spring還提供了SimpleHttpInvokerServiceExporter類供選擇。
服務端配置:
服務聲明:
在Spring配置檔案中聲明一個HttpInvokerServiceExporter類的bean,共三部分:
--服務名稱(如helloExporter)
--服務類型(如com.stevex.demo.HelloService)
--服務實作類,一般引用其它bean(如helloService)
6
<code><</code><code>bean</code> <code>name</code><code>=</code><code>"helloExporter"</code>
<code> </code><code>class</code><code>=</code><code>"org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter"</code><code>></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"service"</code> <code>ref</code><code>=</code><code>"helloService"</code><code>></</code><code>property</code><code>></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"serviceInterface"</code> <code>value</code><code>=</code><code>"com.stevex.demo.HelloService"</code><code>></code>
<code> </code><code></</code><code>property</code><code>></code>
<code> </code><code></</code><code>bean</code><code>></code>
服務URL關聯:
在web.xml中聲明一個與服務與服務名稱同名的Servlet(當然這個Servlet類Spring已經提供即HttpRequestHandlerServlet,這家夥的作用就是直接把強求扔給同名的bean),然後聲明servlet-mapping将其map到指定URL,這樣客戶就可以通過這個URL通路到對應服務。
7
8
9
10
<code><</code><code>servlet</code><code>></code>
<code> </code><code><</code><code>servlet-name</code><code>>helloExporter</</code><code>servlet-name</code><code>></code>
<code> </code><code><</code><code>servlet-class</code><code>></code>
<code> </code><code>org.springframework.web.context.support.HttpRequestHandlerServlet</code>
<code> </code><code></</code><code>servlet-class</code><code>></code>
<code> </code><code></</code><code>servlet</code><code>></code>
<code> </code><code><</code><code>servlet-mapping</code><code>></code>
<code> </code><code><</code><code>url-pattern</code><code>>/remoting/HelloService</</code><code>url-pattern</code><code>></code>
<code> </code><code></</code><code>servlet-mapping</code><code>></code>
用戶端配置:
在spring bean配置檔案中建立一個類HttpInvokerProxyFactoryBean的bean,指定serviceUrl屬性為伺服器端的服務提供的URL,serviceInterface屬性為伺服器端配置的服務類型。
<code><</code><code>bean</code> <code>id</code><code>=</code><code>"remoteHelloService"</code>
<code> </code><code>class</code><code>=</code><code>"org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean"</code><code>></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"serviceUrl"</code>
<code> </code><code>value</code><code>=</code><code>"http://localhost:8080/demo/remoting/HelloService"</code> <code>/></code>
<code> </code><code><</code><code>property</code> <code>name</code><code>=</code><code>"serviceInterface"</code>
<code> </code><code>value</code><code>=</code><code>"com.stevex.demo.HelloService"</code> <code>/></code>
服務端實作:
因為服務端需要提供HTTP請求服務,而且是基于Servlet的,是以服務端需要跑在如Tomcat這樣的Servlet Web容器上;服務類隻要是普通的POJO即可,沒有特殊要求:
<code>@Service</code><code>(</code><code>"helloService"</code><code>)</code>
<code>public</code> <code>class</code> <code>HelloServiceImpl </code><code>implements</code> <code>HelloService {</code>
<code> </code><code>@Override</code>
<code> </code><code>public</code> <code>String hello() { </code>
<code> </code><code>return</code> <code>"Hello Stevex, I am invoked by Spring HTTP Invoker!"</code><code>;</code>
<code> </code><code>}</code>
<code>}</code>
<code>public</code> <code>interface</code> <code>HelloService {</code>
<code> </code><code>public</code> <code>String hello();</code>
用戶端實作:
因為用戶端依賴服務端的服務類,是以需要設定類路徑依賴,可以将class檔案(或者jar包)拷貝到用戶端。
11
<code>public</code> <code>class</code> <code>HelloClient {</code>
<code> </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>
<code> </code><code>GenericXmlApplicationContext ctx = </code><code>new</code> <code>GenericXmlApplicationContext();</code>
<code> </code><code>ctx.load(</code><code>"classpath:http-invoker-app-context.xml"</code><code>);</code>
<code> </code><code>ctx.refresh();</code>
<code> </code><code>HelloService helloService = ctx.getBean(</code><code>"remoteHelloService"</code><code>,</code>
<code> </code><code>HelloService.</code><code>class</code><code>);</code>
<code> </code>
<code> </code><code>System.out.println(helloService.hello());</code>
全部搞定後,将伺服器先跑起來,然後運作用戶端程式就可以看到調用結果了,不知道性能如何,有空測試測試!
<a href="http://down.51cto.com/data/2364013" target="_blank">附件:http://down.51cto.com/data/2364013</a>
本文轉自sarchitect 51CTO部落格,原文連結:http://blog.51cto.com/stevex/1353236,如需轉載請自行聯系原作者