Spring 遠程調用java
遠程調用是客戶端應用和服務端之間的會話。在客戶端上所須要的一些功能並不包括在該應用的職能範圍內。因此應用向能提供這些功能的其餘系統尋求幫助。遠程的應用經過遠程服務把這些功能公開出來。
1、Spring遠程調用概覽
Spring爲各類遠程訪問技術的集成提供了工具類。Spring遠程支持是由普通(Spring)POJO實現的,這使得開發具備遠程訪問功能的服務變得至關容易。
Spring遠程調用支持6種不一樣的RPC模式:遠程方法調用(RMI)、Caucho的Hessian和Burlap、Spring本身的HTTP invoker、EJB和使用JAX-RPC 的Web Services。
RPC模式
在何種狀況下有用
遠程方法調用(RMI)
不考慮網絡限制(如防火牆)時,訪問/公開基於Java的服務
Hessian或 Burlap
考慮網絡限制時,經過HTTP訪問/公開基於Java的服務
HTTP invoker
考慮網絡限制時,訪問/公開基於Spring的服務
EJB
訪問用EJB實現的遺留的J2EE系統
JAX-RPC
訪問Web Services
其中(來自Spring2.0參考手冊):
l 遠程方法調用(RMI)。經過使用 RmiProxyFactoryBean和 RmiServiceExporter,Spring同時支持傳統的RMI(使用java.rmi.Remote接口和java.rmi.RemoteException)和經過RMI調用器實現的透明遠程調用(支持任何Java接口)。
l Spring的HTTP調用器。Spring提供了一種特殊的容許經過HTTP進行Java串行化的遠程調用策略,支持任意Java接口(就像RMI調用器)。相對應的支持類是 HttpInvokerProxyFactoryBean和 HttpInvokerServiceExporter。
l Hessian。經過 HessianProxyFactoryBean和 HessianServiceExporter,可使用Caucho提供的基於HTTP的輕量級二進制協議來透明地暴露服務。
l Burlap。 Burlap是Caucho的另一個子項目,能夠做爲Hessian基於XML的替代方案。Spring提供了諸如 BurlapProxyFactoryBean和 BurlapServiceExporter的支持類。
l JAX RPC。Spring經過JAX-RPC爲遠程Web服務提供支持。
無論選擇哪一種遠程模式,你會發現Spring對每一種模式的支持中貫穿着一個共同的風格。這就意味着你一旦理解了Spring如何配置並使用其中的一種模式,當你決定使用另外一種不一樣的模式的時候,你將擁有很是低的學習曲線。
在全部的模式中,服務能夠做爲Spring管理的Bean配置到你的應用中。這是用一個代理工廠Bean實現的,這個Bean使你能把遠程服務看成本地對象同樣置入到其餘Bean的屬性中。
客戶端發起對代理的調用,好像是代理提供了這些服務的功能同樣。代理表明客戶端和遠程服務交流。它處理鏈接的具體狀況,並向遠程服務發起遠程調用。
在服務端,你可以把任何Spring管理的Bean的功能公開成爲一個遠程服務,可以使用在表6.1中所列的任何模式(除了EJB和JAX-RPC)。
不論開發的是使用遠程服務的代碼,仍是實現那些服務的代碼,或者兩者兼而有之,在Spring中,使用遠程服務純粹是個配置問題。你不用寫任何Java代碼來支持遠程調用。你的服務Bean沒必要關心它們是否被捲入到RPC裏(雖然任何傳遞給遠程調用的Bean或從遠程調用返回的Bean可能須要實現java.io.Serializable)。
2、與RMI一塊兒工做
1.鏈接RMI服務
Spring的RmiProxyFactoryBean是一個工廠Bean,能建立一個指向RMI服務的代理。用RmiProxyFactoryBean來引用一個RMI PaymentService是很是簡單的,只要在Spring配置文件中聲明下面的<bean>:
<bean id="paymentService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value>rmi://${paymenthost}/PayService</value>
</property>
<property name="serviceInterface">
<value>com.springinaction.payment.PaymentService</value>
</property>
</bean>
RMI服務的URL是經過serviceUrl屬性設置的。這裏,服務被命名爲PayService,而且是在一臺名字用一個屬性佔位符配置的機器上(參考第2章的2.4.3節)。serviceInterface屬性指明瞭這個服務所實現的接口,客戶端經過這個接口調用在這個服務裏的方法。
把這個支付服務定義爲一個Spring管理的Bean,你就能把它做爲一個合做者置入到另外的Bean上,就像你對任何非遠程的Bean作的那樣。舉例來講,假設StudentServiceImpl須要使用這個支付服務來批准一張信用卡的支付。你就使用如下代碼把RMI服務置入到StudentServiceImpl中:
<bean id="studentService"
class="com.springinaction.training.service.StudentServiceImpl">
…
<property name="paymentService">
<ref bean="paymentService"/>
</property>
…
</bean>
StudentServiceImpl甚至不須要知道它處理的是一個RMI服務。它只是經過注入機制接收PaymentService對象,沒必要關心它是從哪裏來的。此外,代理會捕獲任何可能被這個服務拋出的RemoteException,並把它們做爲運行時間異常從新拋出,這樣,你能夠安全地忽略這些異常。這也讓遠程服務Bean和這個服務的另外實現之間的交換成爲可能——或許是不一樣的遠程服務,或者有多是單元測試時的一個模擬實現。
2.輸出RMI服務
Spring提供了比較簡單的發佈RMI服務的方法:使用POJO。開始以前,你須要寫這個服務的接口:
publicinterface PaymentService
{
public String authorizeCreditCard(String cardNumber, String cardHolderName, int expireMonth, int expireYear, float amount) throws AuthorizationException;
publicvoid settlePayment(String authCode, int merchantNumber, float amount) throws SettlementException;
}
因爲服務接口不是從java.rmi.Remote繼承的,它的方法都不拋出java.rmi.RemoteException,這點讓這個接口簡短了不少。但更重要的是,客戶端經過這個接口訪問支付服務時,將再也不須要捕捉那些它們可能無法處理的異常了。下一步,定義服務的實現類:
publicclass PaymentServiceImpl implements PaymentService
{
public PaymentServiceImpl() {}
public String authorizeCreditCard(String creditCardNumber, String cardHolderName, int expirationMonth, int expirationYear, float amount) throws AuthorizationException
{
// String authCode = ...;
// implement authorization
return authCode;
}
publicvoid settlePayment(String authCode, int accountNumber, float amount) throws SettlementException
{
// implement settlement
}
}
你要作的下一件事就是在Spring的配置文件裏把PaymentServiceImpl配置爲一個<bean>:
<bean id="paymentService" class="org.springframework.payment.PaymentServiceImpl">
…
</bean>
PaymentServiceImpl沒有設置RMI所固有的特性。它僅僅是一個適合在Spring配置文件中聲明的簡單的POJO。事實上,徹底有可能在非遠程方式中,經過直接把它置入到客戶端裏,來使用這個實現。
3、使用Hessian和Burlap的遠程調用
Hessian和Burlap是Caucho Technology(http://www.caucho.com)提供的兩種解決方法,是基於HTTP的輕量級遠程服務。它們都致力於經過把它們的API和通訊協議變得儘量的簡單,來簡化Web服務。
事實上,Hessian和Burlap是同一個問題的兩個方面,但每一個都服務於略微不一樣的目的。Hessian,像RMI那樣,使用二進制消息來創建客戶端和服務端之間的交流。但與其餘二進制遠程技術(如RMI)不一樣的是,它的二進制消息能夠移植到其餘非Java的語言中。
Burlap是一種基於XML的遠程技術,這使得它天然而然地能夠移植到任何能夠解析XML的語言中。正因爲它的XML,比起Hessian的二進制格式來,它的可讀性更強。但和其餘基於XML的遠程技術(例如SOAP或XML-RPC)不一樣,Burlap的消息結構是儘量的簡單,不須要額外的外部定義語言(如WSDL或IDL等)。
如何在Hessian和Burlap之間作選擇。很大程度上說,它們是同樣的。唯一的不一樣就是Hessian的消息是二進制的,而Burlap的消息是XML。因爲Hessian的消息是二進制的,因此它在帶寬上更佔優點。但若是可讀性對你來講很重要的話(如出於調試的目的)或者你的應用將和沒有Hessian實現(任何除了Java或Python)的語言交流,那麼Burlap的XML消息會是更好的選擇。
1.訪問Hessian/Burlap服務
全部RMI的細節都包含在Spring配置文件的Bean的配置裏。這樣作的好處就是,因爲客戶端忽略了服務的實現,從一個RMI客戶端轉到Hessian客戶端是極其簡單的,不須要改變任何客戶端代碼。
壞處就是,若是你真地喜歡寫代碼的話,那麼這一節就可能讓你有點兒失望了。由於寫基於RMI服務的客戶端代碼和基於Hessian服務的客戶端代碼唯一的不一樣就是你將使用Spring的HessianProxyFactoryBean來代替RmiProxyFactoryBean。客戶端代碼中基於Hessian的支付服務能夠用如下代碼聲明:
<bean id="paymentService" class="org.springframework.
?remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl">
<value>http://${serverName}/${contextPath}/pay.service</value>
</property>
<property name="serviceInterface">
<value>com.springinaction.payment.PaymentService</value>
</property>
</bean>
就像基於RMI的服務那樣,serviceInterface屬性指定這個服務實現的接口。而且,如同RmiProxyFactoryBean,serviceUrl代表這個服務的URL。既然Hessian是基於HTTP的,固然應該在這裏設置一個HTTP URL了(你將在下一節中看到這個URL是如何得來的)。
事實證實,寫一個Burlap服務是一樣無趣的。兩者唯一的不一樣就是,你使用BurlapProxyFactoryBean代替HessianProxyFactoryBean:
<bean id="paymentService" class="org.springframework.
?remoting.caucho.BurlapProxyFactoryBean">
<property name="serviceUrl">
<value>http://${serverName}/${contextPath}/pay.service</value>
</property>
<property name="serviceInterface">
<value>com.springinaction.payment.PaymentService</value>
</property>
</bean>
儘管咱們以爲在RMI、Hessian和Burlap服務之間稍微不一樣的配置是很沒有樂趣的,但這個單調偏偏是有好處的。它意味着你不費吹灰之力就能夠在各類Spring支持的遠程技術之間轉換,無須去學習一個全新的模型。你一旦配置了一個對RMI服務的引用,把它從新配置爲Hessian或Burlap服務也是很輕鬆的工做。
2.用Hessian或Burlap公開Bean的功能
輸出一個Hessian服務:
在Spring裏輸出一個Hessian服務和在Spring裏實現一個RMI服務驚人地類似。爲把支付服務公開爲RMI服務,你得在Spring配置文件中配置一個RmiServiceExporter Bean。很是相似的,把支付服務公開爲Hessian服務,你也須要配置一個exporter Bean。只不過這一次用的是HessianServiceExporter:
<bean name="hessianPaymentService" class="org.springframework.
?remoting.caucho.HessianServiceExporter">
<property name="service">
<ref bean="paymentService"/>
</property>
<property name="serviceInterface">
<value>com.springinaction.payment.PaymentService</value>
</property>
</bean>
HessianServiceExporter在Hessian服務中實現的功能和RmiServiceExporter在RMI服務中的功能是徹底同樣的。那就是說,它把一個Bean的公共方法公開爲一個Hessian服務的方法。
正如RmiServiceExporter,service屬性中被置入了實現這個服務的Bean的引用。這裏,這個service屬性綁定的是paymentService Bean的引用。serviceInterface屬性用來表示PaymentService是這個服務所實現的接口。
然而,和RmiServiceExporter不一樣,你不須要設置serviceName屬性。在RMI中,serviceName屬性用來在RMI註冊表中註冊一個服務。Hessian沒有註冊表,所以就沒有必要命名一個Hessian服務。
配置Hessian控制器:
RmiServiceExporter和HessianServiceExporter另一個主要的區別就是,因爲Hessian是基於HTTP的,因此HessianServiceExporter被實現成Spring MVC的Controller。這就是說,爲了使用輸出的Hessian服務,你須要完成兩個額外的配置步驟:
1.在你的Spring配置文件中配置一個URL處理器,來分發Hessian服務的URL給適當的Hessian服務Bean。
2.在web.xml中配置一個Spring的DispatcherServlet,並把你的應用部署爲web應用。
輸出一個Burlap服務:
把Spring管理的Bean做爲Burlap服務輸出。用Spring的BurlapServiceExporter來代替HessianServiceExporter就能完成這項任務:
<bean name="burlapPaymentService" class="org.springframework.
?remoting.caucho.BurlapServiceExporter">
<property name="service">
<ref bean="paymentService"/>
</property>
<property name="serviceInterface">
<value>com.springinaction.payment.PaymentService</value>
</property>
</bean>
你會發現,除了Bean的名字(徹底是任意的)和使用了BurlapServiceExporter之外,這個Bean和hessianPaymentService是同樣的。配置Burlap服務和配置Hessian服務的其餘方面也是同樣的,這也就包括了須要建一個URL處理器和DispatcherServlet。Hessian和Burlap解決了RMI頭疼的防火牆問題。
4、使用HTTP invoker
1.經過HTTP訪問服務
訪問一個HTTP invoker服務,你須要使用HttpInvokerProxyFactoryBean。要讓支付服務做爲一個HTTP invoker服務公開,得配置一個Bean,用HttpInvokerProxyFactoryBean來代理它,以下所示:
<bean id="paymentService" class= "org.springframework.remoting.
?httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl">
<value>http://${serverName}/${contextPath}/pay.service</value>
</property>
<property name="serviceInterface">
<value>com.springinaction.payment.PaymentService</value>
</property>
</bean>
serviceInterface屬性仍然用來表示這個支付服務所實現的接口;serviceUrl屬性仍然是用來表示遠程支付服務的位置。因爲HTTP invoker是基於HTTP的,如同Hessian和Burlap同樣,serviceUrl就能包含與Hessian和Burlap版本的Bean裏同樣的URL。
2.把Bean做爲HTTP服務公開
使用HttpInvokerServiceExporter把Bean的方法輸出爲遠程方法,面的Bean的定義展現瞭如何把paymentService Bean做爲一個遠程的基於HTTP invoker的服務輸出:
<bean id="httpPaymentService" class="org.springframework.remoting.
?httpinvoker.HttpInvokerServiceExporter">
<property name="service">
<ref bean="paymentService"/>
</property>
<property name="serviceInterface">
<value>com.springinaction.payment.PaymentService</value>
</property>
</bean>
基於HTTP invoker的服務,顧名思義,是基於HTTP的,就像Hessian和Burlap服務同樣。而且,也和HessianServiceExporter和BurlapServiceExporter那樣,HttpInvokerServiceExporter也是一個Spring的Controller。這就意味着你須要創建一個URL處理器,把HTTP URL映射到服務上:
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/pay.service">httpPaymentService</prop>
</props>
</property>
</bean>
Spring的HTTP invoker是做爲一個一箭雙鵰的遠程調用解決方案出現的,把HTTP交流的簡單性和Java內置的對象序列化機制結合起來。這讓HTTP invoker服務成爲一個引人注目的對RMI或是對Hessian/Burlap的替代品。
要記住HTTP invoker有個重大的限制,它是一個只在Spring框架中提供的遠程調用解決方案。這就意味着客戶端和服務器端都必須是使用Spring的應用。
五.使用EJB
雖然Spring提供了大量的功能,讓POJO具備EJB的能力,但你或許不能老是享受在徹底沒有EJB的項目上工做的奢侈。一方面,你可能會接觸一些其餘系統,它們的功能是經過無狀態的會話EJB開放出來的。另外一方面,你可能被放在一個項目中,因爲正統技術(或者多是政治)的緣由,你不得不寫EJB代碼。
無論你的應用是EJB客戶端,仍是你必須寫EJB自己,你都不須要爲了用EJB,徹底放棄Spring帶來的好處。Spring有兩種方法提供對EJB的支持:
? Spring能讓你在Spring的配置文件裏,把EJB做爲Bean來聲明。這樣,把EJB引用置入到其餘Bean的屬性裏就成爲可能了,好像EJB就是另外一個POJO。
? Spring能讓你寫EJB,讓EJB成爲Spring配置的Bean的代理的工做。
6、使用JAX-RPC的Web Service
JAX-RPC是「基於XML的遠程調用的Java API(Java APIs for XML-based remote procedure call)」的縮寫。這是一個口語化的詞,僅僅意味着JAX-RPC是Java程序使用XML訪問遠程服務的一種方式。特別地,這個服務是指用SOAP(Simple Object Access Protocol)協議公開它們的功能的web service。
7、小結
Spring提供了遠程服務的支持,讓使用遠程服務和使用常規的JavaBean同樣簡單。
在客戶端,Spring提供了代理工廠Bean,能讓你在Spring應用中配置遠程服務。無論是使用RMI、Hessian、Burlap、HTTP invoker、EJB、仍是Web service,你均可以把遠程服務置入到你的應用裏,好像它們是POJO同樣。Spring甚至捕獲了全部拋出的RemoteException,並在發生異常的地方從新拋出運行時RemoteAccessException,讓你的代碼從處理可能不可恢復的異常中解放出來。
Spring的遠程調用我不知何時才能用上,在這裏在不太理解的基礎上對書做了簡單的摘抄,先留個記號等之後用着了在回頭學習。web