Spring - Java/J2EE Application Framework 应用框架 第 16 章 通过Spring使用远程访问和web服务
第?16?章?通過Spring使用遠程訪問和web服務(wù)
16.1.?簡介
Spring提供類用于集成各種遠程訪問技術(shù)。這種對遠程訪問的支持可以降低你在用POJO實現(xiàn)支持遠程訪問業(yè)務(wù)時的開發(fā)難度。目前,Spring提供對下面四種遠程訪問技術(shù)的支持:
-
遠程方法調(diào)用(RMI)。通過使用RmiProxyFactoryBean和RmiServiceExporter,Spring支持傳統(tǒng)的RMI(使用java.rmi.Remote interfaces 和 java.rmi.RemoteException)和通過RMI調(diào)用器(可以使用任何Java接口)的透明遠程調(diào)用。
-
Spring的HTTP調(diào)用器。Spring提供一種特殊的遠程調(diào)用策略支持任何Java接口(象RMI調(diào)用器一樣),它允許Java序列化能夠通過HTTP傳送。對應(yīng)的支持類是HttpInvokerProxyFactoryBean和HttpInvokerServiceExporter。
-
Hessian。通過使用HessianProxyFactoryBean和HessianServiceExporter,你可以使用Caucho提供的輕量級基于HTTP的二進制協(xié)議透明地提供你的業(yè)務(wù)。
-
Burlap。Burlap是基于XML的,它可以完全代替Hessian。Spring提供的支持類有BurlapProxyFactoryBean和BurlapServiceExporter。
-
JAX RPC (TODO).
當(dāng)討論Spring對遠程訪問的支持時,我們將使用下面的域模型和對應(yīng)的業(yè)務(wù):
// Account domain object public class Account implements Serializable{private String name;public String getName();public void setName(String name) {this.name = name;} } // Account service public interface AccountService {public void insertAccount(Account acc);public List getAccounts(String name); } // ... and corresponding implement doing nothing at the moment public class AccountServiceImpl implements AccountService {public void insertAccount(Account acc) {// do something}public List getAccounts(String name) {// do something} }我們先演示使用RMI向遠程客戶提供業(yè)務(wù),并且會談到使用RMI的缺點。然后我們將繼續(xù)演示一個Hessian的例子。
16.2.?使用RMI提供業(yè)務(wù)
使用Spring的RMI支持,你可以透明地通過RMI提供你的業(yè)務(wù)。在配置好Spring的RMI支持后,你會看到一個和遠程EJB類似的配置,除了沒有對安全上下文傳遞和遠程事務(wù)傳遞的標(biāo)準(zhǔn)支持。當(dāng)使用RMI調(diào)用器時,Spring對這些額外的調(diào)用上下文提供捕獲,所以你可以插入你的安全框架或安全信任邏輯。
16.2.1.?使用RmiServiceExporter提供業(yè)務(wù)
使用RmiServiceExporter,我們可以將AccountServer對象作為RMI對象輸出接口。這個接口可以使用RmiProxyFactoryBean訪問,或使用簡單RMI把該接口當(dāng)作傳統(tǒng)RMI業(yè)務(wù)來訪問。RmiServiceExporter支持通過RMI調(diào)用器提供任何非RMI業(yè)務(wù)。
當(dāng)然,我們首先得在Spring的BeanFactory中設(shè)置我們的業(yè)務(wù):
<bean id="accountService" class="example.AccountServiceImpl"><!-- any additional properties, maybe a DAO? --> </bean>接下來,我們使用RmiServiceExporter提供我們的業(yè)務(wù):
<bean class="org.springframework.remoting.rmi.RmiServiceExporter"><!-- does not necessarily have to be the same name as the bean to be exported --><property name="serviceName"><value>AccountService</value></property><property name="service"><ref bean="accountService"/></property><property name="serviceInterface"><value>example.AccountService</value></property><!-- defaults to 1099 --><property name="registryPort"><value>1199</value></property> </bean>正如你看到的,我們更換了RMI注冊的端口。通常,你的應(yīng)用服務(wù)器會維護RMI注冊,我們最好不要干擾它。業(yè)務(wù)名被用來綁定業(yè)務(wù)。所以現(xiàn)在,業(yè)務(wù)就綁定在rmi://HOST:1199/AccountService上。我們將在客戶端使用URL來連接業(yè)務(wù)。
注意:我們漏了一個屬性,就是servicePort屬性,它缺省值為0。這個意味著該業(yè)務(wù)使用匿名端口通訊。當(dāng)然你也可以指定一個端口。
16.2.2.?客戶端連接業(yè)務(wù)
我們的客戶端是一個使用AccountService管理賬戶的簡單對象:
public class SimpleObject {private AccountService accountService;public void setAccountService(AccountService accountService) {this.accountService = accountService;} }為了在客戶端連接業(yè)務(wù),我們建立另一個bean工廠,它包含這個簡單對象和業(yè)務(wù)連接的配置信息:
<bean class="example.SimpleObject"><property name="accountService"><ref bean="accountService"/></bean> </bean><bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"><property name="serviceUrl"><value>rmi://HOST:1199/AccountService</value></property><property name="serviceInterface"><value>example.AccountService</value></property> </bean>這就是我們在客戶端訪問遠程賬戶業(yè)務(wù)所需要做的。Spring透明地創(chuàng)建一個調(diào)用器,通過RmiServiceExporter遠程提供賬戶業(yè)務(wù)。在客戶端,我們使用RmiProxyFactoryBean來使用該業(yè)務(wù)。
16.3.?使用Hessian或Burlap通過HTTP遠程調(diào)用業(yè)務(wù)
Hessian提供了一個基于HTTP的二進制遠程協(xié)議。它由Caucho創(chuàng)建,更多有關(guān)Hessian的信息可以訪問http://www.caucho.com。
16.3.1.?為Hessian建立DispatcherServlet
Hessian使用一個特定的servlet來通過HTTP通訊。使用Spring的DispatcherServlet概念,你可以很容易地創(chuàng)建這樣的servlet來提供你的業(yè)務(wù)。首先我們必須在你的應(yīng)用中創(chuàng)建一個新的servlet(下面來自web.xml):
<servlet><servlet-name>remote</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup> </servlet>你可能熟悉Spring的DispatcherServlet概念,如果是的話,你得在WEB-INF目錄下建立一個應(yīng)用上下文,remote-servlet.xml?。這個應(yīng)用上下文會在下一節(jié)中使用。
16.3.2.?使用HessianServiceExporter提供你的bean
在這個新的應(yīng)用上下文remote-servlet.xml中,我們將創(chuàng)建一個HessianServiceExporter來輸出你的業(yè)務(wù):
<bean id="accountService" class="example.AccountServiceImpl"><!-- any additional properties, maybe a DAO? --> </bean><bean name="/AccountService" class="org.springframework.remoting.caucho.HessianServiceExporter"><property name="service"><ref bean="accountService"/></property><property name="serviceInterface"><value>example.AccountService</value></property> </bean>現(xiàn)在我們準(zhǔn)備在客戶端連接這個業(yè)務(wù)。我們使用BeanNameUrlHandlerMapping,就不需要指定處理器映射將請求(url)映射到業(yè)務(wù)上,因此業(yè)務(wù)提供在http://HOST:8080/AccountService上。
16.3.3.?客戶端連接業(yè)務(wù)
我們在客戶端使用HessianProxyFactoryBean來連接業(yè)務(wù)。和RMI例子中的原則一樣。我們將創(chuàng)建一個單獨的bean工廠或應(yīng)用上下文,在SimpleObject使用AccountService來管理賬戶的地方將會提到下列bean:
<bean class="example.SimpleObject"><property name="accountService"><ref bean="accountService"/></property> </bean><bean id="accountService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"><property name="serviceUrl"><value>http://remotehost:8080/AccountService</value></property><property name="ServiceInterface"><value>example.AccountService</value></property> </bean>就是這樣簡單。
16.3.4.?使用Burlap
我們不在這里討論Burlap,它只不過是Hessian的基于XML實現(xiàn)。因為它和上面的Hessian的例子以相同的方式配置。只要你把Hessian替換成Burlap就可以了。
16.3.5.?在通過Hessian或Burlap輸出的業(yè)務(wù)中應(yīng)用HTTP基本認證
Hessian和Burlap的優(yōu)點之一就是我們能很容易地應(yīng)用HTTP認證,因為兩者都是基于HTTP的協(xié)議。例如,普通的HTTP服務(wù)器安全機制可以很容易地通過使用web.xml安全功能來應(yīng)用。通常,你不會為每個用戶都建立不同的安全信任,而是在Hessian/Burlap的ProxyFactoryBean中定義可共享的信任(和JDBC DataSource相類似)。
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><property name="interceptors"><list><ref bean="authorizationInterceptor"/></list></property> </bean><bean id="authorizationInterceptor" class="org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor"><property name="authorizedRoles"><list><value>administrator</value><value>operator</value></list></property> </bean>這個例子中,我們用到了BeanNameUrlHandlerMapping,并設(shè)置了一個攔截器,它只允許管理員和操作員調(diào)用這個應(yīng)用上下文中的bean。
注意:當(dāng)然,這個例子并沒有演示靈活的安全設(shè)施。如果考慮更靈活的安全設(shè)置,可以去看看Acegi Security System,http://acegisecurity.sourceforge.net。
16.4.?使用HTTP調(diào)用器輸出業(yè)務(wù)
和Burlap和Hessian使用自身序列化機制的輕量級協(xié)議相反,Spring HTTP調(diào)用器使用標(biāo)準(zhǔn)Java序列化機制來通過HTTP輸出業(yè)務(wù)。如果你的參數(shù)或返回值是復(fù)雜類型,并且不能通過Hessian和Burlap的序列化機制序列化,HTTP調(diào)用器就很有優(yōu)勢(參閱下一節(jié),選擇遠程技術(shù)時的考慮)。
實際上,Spring可以使用J2SE提供的標(biāo)準(zhǔn)功能或Commons的HttpClient來實現(xiàn)HTTP調(diào)用。如果你需要更先進,更好用的功能,就使用后者。你可以參考jakarta.apache.org/commons/httpclient。
16.4.1.?輸出業(yè)務(wù)對象
為業(yè)務(wù)對象設(shè)置HTTP調(diào)用器和你在Hessian或Burlap中使用的方式類似。就象Hessian提供HessianServiceExporter,Spring的HTTP調(diào)用器提供了org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter。為了輸出AccountService,使用下面的配置:
<bean name="/AccountService" class="org.sprfr.remoting.httpinvoker.HttpInvokerServiceExporter"><property name="service"><ref bean="accountService"/></property><property name="serviceInterface"><value>example.AccountService</value></property></bean>16.4.2.?在客戶端連接業(yè)務(wù)
同樣,從客戶端連接業(yè)務(wù)與你使用Hessian或Burlap時做的類似。使用代理,Spring可以將你的調(diào)用翻譯成HTTP 的POST請求到指向輸出業(yè)務(wù)的URL。
<bean id="httpInvokerProxy" class="org.sprfr.remoting.httpinvoker.HttpInvokerProxyFactoryBean"><property name="serviceUrl"><value>http://remotehost:8080/AccountService</value></property><property name="serviceInterface"><value>example.AccountService</value></property></bean>就象上面說的一樣,你可以選擇使用你想使用的HTTP客戶端。缺省情況下,HttpInvokerPropxy使用J2SE的HTTP功能,但是你也可以通過設(shè)置httpInvokerRequestExecutor屬性選擇使用Commons HttpClient:
<property name="httpInvokerRequestExecutor"><bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/> </property>16.5.?在選擇這些技術(shù)時的一些考慮
這里提到的每種技術(shù)都有它的缺點。你在選擇這些技術(shù)時,應(yīng)該仔細考慮你的需要,你所輸出的業(yè)務(wù)和你在遠程訪問時傳送的對象。
當(dāng)使用RMI時,通過HTTP協(xié)議訪問對象是不可能的,除非你用HTTP包裹RMI流。RMI是一種很重的協(xié)議,因為他支持完全的對象序列化,這樣的序列化在要求復(fù)雜數(shù)據(jù)結(jié)構(gòu)在遠程傳輸時是非常重要的。然而,RMI-JRMP只能綁定到Java客戶端:它是一種Java-to-Java的遠程訪問的方案。
如果你需要基于HTTP的遠程訪問而且還要求使用Java序列化,Spring的HTTP調(diào)用器是一個很好的選擇。它和RMI調(diào)用器使用相同的基礎(chǔ)設(shè)施,僅僅使用HTTP作為傳輸方式。注意HTTP調(diào)用器不僅只能用在Java-to-Java的遠程訪問,而且在客戶端和服務(wù)器端都必須使用Spring。(Spring為非RMI接口提供的RMI調(diào)用器也要求客戶端和服務(wù)器端都使用Spring)
當(dāng)在異構(gòu)環(huán)境中,Hessian和Burlap就非常有用了。因為它們可以使用在非Java的客戶端。然而,對非Java支持仍然是有限制的。已知的問題包括含有延遲初始化的collection對象的Hibernate對象的序列化。如果你有一個這樣的數(shù)據(jù)結(jié)構(gòu),考慮使用RMI或HTTP調(diào)用器,而不是Hessian。
最后但也很重要的一點,EJB優(yōu)于RMI,因為它支持標(biāo)準(zhǔn)的基于角色的認證和授權(quán),以及遠程事務(wù)傳遞。用RMI調(diào)用器或HTTP調(diào)用器來支持安全上下文的傳遞是可能的,雖然這不是由核心Spring提供:而是由第三方或在定制的解決方案中插入攔截器來解決的。
from:?http://docs.huihoo.com/spring/zh-cn/remoting.html
總結(jié)
以上是生活随笔為你收集整理的Spring - Java/J2EE Application Framework 应用框架 第 16 章 通过Spring使用远程访问和web服务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring - Java/J2EE A
- 下一篇: Spring - Java/J2EE A