欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
SOA實(shí)踐 -- 使用IoC和AOP重構SOA應用
在本文中,作者通過(guò)一個(gè)Web Service訪(fǎng)問(wèn)的實(shí)例,具體描述了SOA應用中所遇到的一系列具體問(wèn)題,并描述如何利用IoC和AOP等技術(shù)進(jìn)行代碼重構,從而構建結構更加良好、靈活的SOA應用。

1.引言

SOA是一種構造分布式系統的方法,它將業(yè)務(wù)應用功能以服務(wù)的形式提供出來(lái),以便更好的復用、組裝和與外部系統集成,從而降低開(kāi)發(fā)成本,提高開(kāi)發(fā)效率。SOA的目標是為企業(yè)構建一個(gè)靈活,可擴展的IT基礎架構來(lái)更好地支持隨需應變的商務(wù)應用。

隨著(zhù)SOA技術(shù)和產(chǎn)品的不斷成熟,現在越來(lái)越多的用戶(hù)開(kāi)始了解并認同SOA的理念,但對SOA項目的實(shí)施還缺乏信心。其主要原因是:SOA應用開(kāi)發(fā)還相對比較復雜。

一年多來(lái),本文作者所在的部門(mén)已經(jīng)從事了許多國內外的SOA項目的實(shí)施和支持工作,積累了許多SOA應用開(kāi)發(fā)經(jīng)驗。我們希望能夠通過(guò)一系列的文章與讀者分享這些想法,幫助您更好地構建SOA應用。

本文將從Web Service調用入手,在解決一系列具體問(wèn)題的過(guò)程中,使用IoC (Inversion of Control) 和AOP (Aspect- Oriented Programming) 等方法重構Web Service的訪(fǎng)問(wèn)代碼,使得業(yè)務(wù)邏輯與Web Service訪(fǎng)問(wèn)解耦,為您提供一個(gè)更加靈活和易于擴展的訪(fǎng)問(wèn)模式。

Spring是一個(gè)流行的輕量級容器,對IoC和AOP提供了良好的支持。本文為您提供了一個(gè)基于Spring的實(shí)現供您下載學(xué)習。示例代碼工程使 用Eclipse3.1/3.02和JDK1.4開(kāi)發(fā), 您還需要Spring 1.2.5和Axis1.3提供的支持。詳細的下載信息請參見(jiàn)參考資源部分。





回頁(yè)首


2.Web Service調用

Web Service是目前實(shí)現SOA應用的一項基本的,適用的技術(shù),它為服務(wù)的訪(fǎng)問(wèn)提供了一個(gè)被廣泛接受的開(kāi)放標準。為了便于說(shuō)明問(wèn)題,我們將使用XMethods 網(wǎng)站(http://www.xmethods.net/)發(fā)布的貨幣兌換服務(wù)作為示例。并針對JAX-RPC 1.1,說(shuō)明如何編寫(xiě)Web Service 的調用代碼。

2.1 示例說(shuō)明

http://xmethods.net 作為最早推出Web Service實(shí)際示例的網(wǎng)站,提供了很多優(yōu)秀的Web Service 樣例。其中有一個(gè)匯率計算服務(wù),可以返回兩個(gè)國家之間的貨幣兌換比例。獲取該服務(wù)的詳細信息,請參考該服務(wù)的服務(wù)描述文檔(獲取WSDL 文檔) 。在此就不具體解析該服務(wù)描述文檔了。讀者可以從WSDL2Java生成的接口中了解該服務(wù)的用法:



public interface CurrencyExchangePortType extends java.rmi.Remote {
public float getRate(String country1, String country2) throws java.rmi.RemoteException;
}

2.2 客戶(hù)端調用方法

JAX-RPC作為Java平臺的RPC服務(wù)調用標準接口,為Web Service客戶(hù)端調用提供了3種方法,分別是DII,動(dòng)態(tài)代理,和靜態(tài)Stub。 DII(Dynamic Invocation Interface)采用直接調用方式,可以在程序中設置諸多的調用屬性,使用較為靈活,但是調用過(guò)程卻相對繁瑣復雜,易造成代碼膨脹且可重用性低,每次調用不同的Web Service都要重復進(jìn)行大量編碼。

JAX-RPC中動(dòng)態(tài)代理(Dynamic Proxy)的方法實(shí)現對Web Service的動(dòng)態(tài)調用,可以在運行時(shí)根據用戶(hù)定義的Client端接口創(chuàng )建適配對象。從而避免了直接操作底層的接口,減少了客戶(hù)端的冗余,屏蔽了調用相關(guān)的復雜性。

使用靜態(tài)Stub和Service Locator是目前最常用的調用方式。JAX-RPC使用靜態(tài)的Stub方式包裝對底層接口的調用,從而提供一種更為簡(jiǎn)便的調用方式。使用該方式需要利 用支持環(huán)境(比如Axis)所提供的工具根據WSDL預生成Web Service客戶(hù)端的實(shí)現代碼。因此如果服務(wù)的WSDL發(fā)生變化,就必須重新生成新的客戶(hù)端代碼并進(jìn)行重新部署。

為了更詳細的了解靜態(tài)Stub的調用方式,您可以將示例代碼的WebServiceClient.jar導入到您現有Eclipse工作區之中。

客戶(hù)端生成代碼包括如下4個(gè)類(lèi):如圖 1 所示:



圖 1: 客戶(hù)端代碼類(lèi)圖

在上圖中包括的幾個(gè)類(lèi)中:

CurrencyExchangePortType:服務(wù)端點(diǎn)接口,定義了Web Service的方法簽名。

CurrencyExchangeService:Service接口,定義了獲取服務(wù)端點(diǎn)接口的方法。

CurrencyExchangeServiceLocator:ServiceLocator類(lèi),實(shí)現了Service接口。

CurrencyExchangeBindingStub: Stub實(shí)現類(lèi),實(shí)現了服務(wù)端點(diǎn)接口,封裝了對Web Service訪(fǎng)問(wèn)的底層邏輯。

使用Stub調用Web Service的過(guò)程也非常簡(jiǎn)單,讀者可以參考清單 1:



清單 1:Web Service 調用代碼示例
try {
//創(chuàng )建ServiceLocator
CurrencyExchangeServiceLocator locator = new
CurrencyExchangeServiceLocator();
//設定端點(diǎn)地址
URL endPointAddress = new URL("http://services.xmethods.net:80/soap");
//創(chuàng )建Stub實(shí)例
CurrencyExchangePortType stub =
locator.getCurrencyExchangePort(endPointAddress);
//設定超時(shí)為120秒
((CurrencyExchangeBindingStub)stub).setTimeout(120000);
//調用Web Service計算人民幣與美元的匯率
float newPrice = stub.getRate("China", "USA") * 100;
} catch (MalformedURLException mex) {
//...
} catch (ServiceException sex) {
//...
} catch (RemoteException rex) {
//...
}





回頁(yè)首


3.重構Web Service調用代碼

3.1 實(shí)例代碼中的"壞味道"

上面的基于Service Locator的Web Service訪(fǎng)問(wèn)代碼雖然簡(jiǎn)單但暴露出以下幾個(gè)問(wèn)題:

1.訪(fǎng)問(wèn)Web Service所需的配置代碼被嵌入應用邏輯之中
在Web Service調用中,我們需要設定一系列必要的參數。比如:服務(wù)端點(diǎn)地址、用戶(hù)名/密碼、超時(shí)設定等等。這些參數在開(kāi)發(fā)和運行環(huán)境中都有可能發(fā)生變化。我們必須提供一種機制:在環(huán)境變化時(shí),不必修改源代碼就可以改變Web Service的訪(fǎng)問(wèn)配置。

2 客戶(hù)端代碼與Web Service訪(fǎng)問(wèn)代碼綁定
在上面的代碼中,業(yè)務(wù)邏輯與Web Service的Stub創(chuàng )建和配置代碼綁定在一起。這也不是一種良好的編程方式??蛻?hù)端代碼只應關(guān)心服務(wù)的接口,而不應關(guān)心服務(wù)的實(shí)現和訪(fǎng)問(wèn)細節。比 如,我們既可以通過(guò)Web Service的方式訪(fǎng)問(wèn)遠程服務(wù),也可以通過(guò)EJB的方式進(jìn)行訪(fǎng)問(wèn)。訪(fǎng)問(wèn)方式對業(yè)務(wù)邏輯應該是透明的。

這種分離客戶(hù)端代碼與服務(wù)訪(fǎng)問(wèn)代碼的方式也有利于測試。這樣在開(kāi)發(fā)過(guò)程中,負責集成的程序員就可能在遠程服務(wù)還未完全實(shí)現的情況下,基于服務(wù)接口編 寫(xiě)集成代碼,并通過(guò)編寫(xiě)POJO(Plain Old Java Object)構建偽服務(wù)實(shí)現來(lái)進(jìn)行單元測試和模擬運行。這種開(kāi)發(fā)方式對于保證分布式系統代碼質(zhì)量具有重要意義。

因此,為了解決上面的問(wèn)題我們需要:

1、將Web Service訪(fǎng)問(wèn)的配置管理與代碼分離;

2、解除客戶(hù)端代碼與遠程服務(wù)之間的依賴(lài)關(guān)系;

3.2 利用IoC模式進(jìn)行重構代碼

我們先介紹在Core J2EE Patterns一書(shū)中提到的一種業(yè)務(wù)層模式:Business Delegate。它所要解決的問(wèn)題是屏蔽遠程服務(wù)訪(fǎng)問(wèn)的復雜性。它的主要思想就是將Business Delegate作為遠程服務(wù)的客戶(hù)端抽象,隱藏服務(wù)訪(fǎng)問(wèn)細節。Business Delegate還可以封裝并改變服務(wù)調用過(guò)程,比如將遠程服務(wù)調用拋出的異常(例如RemoteException)轉換為應用級別的異常類(lèi)型。

其類(lèi)圖如圖 2 所示:



圖 2:Business Delegate 模式的類(lèi)圖圖解

Business Delegate模式實(shí)現很好地實(shí)現了客戶(hù)端與遠程訪(fǎng)問(wèn)代碼的解耦,但它并不關(guān)注Delegate與遠程服務(wù)之間的解耦。為了更好解決Business Delegate和遠程服務(wù)之間的依賴(lài)關(guān)系,并更好地進(jìn)行配置管理,我們可以用IoC模式來(lái)加以解決。

IoC(Inversion of Contro)l意為控制反轉,其背后的概念常被表述為"好萊塢法則":"Don‘t call me, I‘ll call you." IoC將一部分責任從應用代碼交給framework(或者控制器)來(lái)做。通過(guò)IoC可以實(shí)現接口和具體實(shí)現的高度分離,降低對象之間的耦合程度。 Spring是一個(gè)非常流行的IoC容器,它通過(guò)配置文件來(lái)定義對象的生命周期和依賴(lài)關(guān)系,并提供了良好的配置管理能力。

現在我們來(lái)重構我們的Web Service應用程序,我們首先為Business Delegate定義一個(gè)接口類(lèi)型,它提供了一個(gè)應用級組件接口,所有客戶(hù)端都應通過(guò)它來(lái)執行匯率計算,而不必關(guān)心實(shí)現細節,如清單 2 所示:



清單 2:接口定義的代碼示例
Public interface CurrencyExchangeManager {
//貨幣兌換計算
//新價(jià)格 = 匯率 * 價(jià)格
public float calculate(String country1, String country2, float price)
throws CurrencyExchangeException;
}

Business Delegate的實(shí)現非常簡(jiǎn)單,主要工作是包裝匯率計算 Web Service的調用,如清單 3 所示。



清單 3:Business Delegate的代碼示例
public class CurrencyExchangeManagerImpl implements CurrencyExchangeManager {
//服務(wù)實(shí)例
private CurrencyExchangePortType stub;
//獲取服務(wù)實(shí)例
public CurrencyExchangePortType getStub() {
return stub;
}
//設定服務(wù)實(shí)例
public void setStub(CurrencyExchangePortType stub) {
this.stub = stub;
}
//實(shí)現貨幣兌換
public float calculate(String country1, String country2, float price)
throws CurrencyExchangeException {
try {
//通過(guò)Stub調用WebService
float rate = stub.getRate(country1, country2);
return rate * price;
} catch (RemoteException rex) {
throw new CurrencyExchangeException(
"Failed to get exchange rate!", rex);
}
}
}

下面我們需要討論如何利用Spring的IoC機制,來(lái)創(chuàng )建和配置對象,并定義它們的依賴(lài)關(guān)系。

Spring利用類(lèi)工廠(chǎng)來(lái)創(chuàng )建和配置對象。在Spring框架中,已經(jīng)為基于JAX-RPC的Web Service調用提供了一個(gè)客戶(hù)端代理的類(lèi)工廠(chǎng)實(shí)現:JaxRpcPortProxyFactoryBean。在配置文件bean.xml中,我們將使 用JaxRpcPortProxyFactoryBean來(lái)創(chuàng )建和配置Web Service的客戶(hù)端代理"CurrencyExchangeService",如清單 5 所示。我們還將定義一個(gè)名為"CurrencyExchangeManager"的CurrencyExchangeManagerImpl實(shí)例,并建立 它與CurrencyExchangeService之間的依賴(lài)關(guān)系。有關(guān)Spring 配置和JaxRpcPortProxyFactoryBean的使用細節請參見(jiàn)參考資料。



清單 5:bean.xml的配置文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="CurrencyExchangeService"
class="org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean">
<property name="serviceInterface">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.
CurrencyExchangePortType</value>
</property>
<property name="wsdlDocumentUrl">
<value>http://www.xmethods.net/sd/2001/CurrencyExchangeService.
wsdl</value>
</property>
<property name="namespaceUri">
<value>http://www.xmethods.net/sd/CurrencyExchangeService.
wsdl</value>
</property>
<property name="serviceName">
<value>CurrencyExchangeService</value>
</property>
<property name="portName">
<value>CurrencyExchangePort</value>
</property>
<property name="endpointAddress">
<value>http://services.xmethods.net:80/soap</value>
</property>
</bean>
<bean id="CurrencyExchangeManager"
class="test.ws.CurrencyExchangeManagerImpl">
<property name="stub">
<ref bean="CurrencyExchangeService"/>
</property>
</bean>
</beans>

最后我們創(chuàng )建一個(gè)測試程序來(lái)驗證我們的代碼,如清單6 所示:



清單 6:測試代碼
public class Main {
// For test only
public static void main(String[] args) {
// Spring Framework將根據配置文件創(chuàng )建并配置CurrencyExchangeManager實(shí)例
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
// 獲取CurrencyExchangeManager實(shí)例
CurrencyExchangeManager manager = (CurrencyExchangeManager) ctx
.getBean("CurrencyExchangeManager");
try {
System.out.println(manager.calculate("China", "USA", 100));
System.out.println(manager.calculate("China", "Japan", 200));
System.out.println(manager.calculate("China", "USA", 200));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

此時(shí)運行測試客戶(hù)端,等待片刻將會(huì )看見(jiàn)測試結果,如清單 7 所示:



清單 7:測試結果。
12.34
2853.26
24.68

注:該結果會(huì )隨著(zhù)匯率的變化而出現不同的值。

該程序的類(lèi)圖和順序圖如圖3及圖4所示:



圖 3:示例程序的類(lèi)圖

從上面的類(lèi)圖我們可以看到,我們的測試程序(Main.java)通過(guò)Spring框架獲取了BusinessDelegate的實(shí)例。而且 Spring 框架還會(huì )根據配置中的依賴(lài)關(guān)系,在運行時(shí)將Web Service的客戶(hù)端代理" 注射"到CurrencyExchangeManagerImpl實(shí)例中,這就是依賴(lài)注入(Dependency Injection)。通過(guò)這種方式解決了應用邏輯和BusinessDelegate之間的依賴(lài)關(guān)系,以及BusinessDelegate的實(shí)現與遠程服務(wù)之間的依賴(lài)關(guān)系,如圖 4 所示。



圖 4: 示例程序的順序圖

Spring框架提供的ApplicationContext實(shí)現會(huì )根據配置文件中的描述信息來(lái)實(shí)現對象生命周期管理,配置管理以及依賴(lài)管理等功 能。這一切對于應用程序是透明的,應用程序代碼只依賴(lài)接口進(jìn)行編程,而無(wú)需考慮其它復雜問(wèn)題。無(wú)論是Web Service的配置發(fā)生變化,或是改用不同的服務(wù)實(shí)現時(shí),都不會(huì )對客戶(hù)端應用代碼的產(chǎn)生影響。這很好地實(shí)現了業(yè)務(wù)邏輯與Web Service調用之間的解耦。

3.3 構建自己的 Web Service代理工廠(chǎng)

Spring所提供的JaxRpcPortProxyFactoryBean封裝了構造Web Service客戶(hù)端代理的細節,可以通過(guò)參數配置來(lái)創(chuàng )建Dynamic Proxy和DII類(lèi)型的Web Service客戶(hù)端代理。(如果您希望深入了解其實(shí)現細節可以參考org.springframework.remoting.jaxrpc包下的源代 碼。)但由于JaxRpcPortProxyFactoryBean需要使用者對WSDL中Port,Service,名空間等概念有深入的了解;而且如 果Web Service使用了復雜數據類(lèi)型,開(kāi)發(fā)人員需要手工定義類(lèi)型映射代碼。所以JaxRpcPortProxyFactoryBean并不適合Web Service的初學(xué)者來(lái)使用。

為了進(jìn)一步簡(jiǎn)化Web Service代理的創(chuàng )建,并幫助讀者更好地理解類(lèi)工廠(chǎng)在Spring框架下的作用。我們提供了一個(gè)基于靜態(tài)Stub的Web Service客戶(hù)端代理工廠(chǎng)實(shí)現。其核心代碼非常簡(jiǎn)單,就是通過(guò)ServiceLocator提供的方法來(lái)創(chuàng )建Web Service客戶(hù)端代理。

其主要代碼如清單8所示:



清單8:靜態(tài)代理工廠(chǎng)的代碼
public class WebServiceStubFactoryBean implements FactoryBean, 
InitializingBean {
private Class serviceInterface;
private Class serviceLocator;
private Object stub;

public void afterPropertiesSet() throws Exception {
//利用serviceLocator和服務(wù)接口創(chuàng )建Web Service客戶(hù)端代理
stub = ((javax.xml.rpc.Service)
serviceLocator.newInstance()).getPort(serviceInterface);
//為Stub設定endpointAddress,usernam, 超時(shí)等參數
preparePortStub((javax.xml.rpc.Stub) stub);
}
public Object getObject() {
// 返回客戶(hù)端代理
return stub;
}
public Class getObjectType() {
// 返回服務(wù)接口
return serviceInterface;
}
public boolean isSingleton() {
return true;
}
}

我們需要修改配置文件bean.xml中有關(guān)Web Service代理創(chuàng )建的部分,讓新的Web Service 代理工廠(chǎng)發(fā)揮作用。如清單9所示:



清單9:修改后的bean.xml的配置文件
<bean id="CurrencyExchangeService" class="test.ws.WebServiceStubFactoryBean">
<property name="serviceInterface">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.CurrencyExchangePortType</value>
</property>
<property name="serviceLocator">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.CurrencyExchangeServiceLocator</value>
</property>
<property name="endpointAddress2">
<value>http://services.xmethods.net:80/soap</value>
</property>
<property name="timeout">
<value>120000</value>
</property>
</bean>

得益于Spring框架,雖然我們已經(jīng)替換了對象的類(lèi)工廠(chǎng),卻并不需要更改應用代碼。通過(guò)Spring框架的IoC機制,我們可以完全使用面向接口的編程方式,而將實(shí)現的創(chuàng )建、配置和依賴(lài)管理交由Spring在運行時(shí)完成。即使實(shí)現發(fā)生了變化,也不需要改變應用程序結構。





回頁(yè)首


4.新的思考

故事并沒(méi)有結束,在開(kāi)發(fā)過(guò)程中,我們又遇到了一系列關(guān)于Web Service調用的問(wèn)題。

4.1性能

系統性能是分布式應用中的一個(gè)重要問(wèn)題。許多用戶(hù)都擔心由Web Service技術(shù)所引入的額外開(kāi)銷(xiāo)是否會(huì )影響到產(chǎn)品的性能。隨著(zhù)技術(shù)的不斷發(fā)展,Web Service引擎性能已經(jīng)有了很大提高,一般來(lái)說(shuō)使用Web Service的系統的性能可以滿(mǎn)足絕大部分應用的需求。但在特定情況下,如果系統性能無(wú)法滿(mǎn)足客戶(hù)需求,我們首先需要對系統性能進(jìn)行科學(xué)地分析和測定才 能定位真正的性能瓶頸。這個(gè)問(wèn)題在上文簡(jiǎn)單的示例中并不難解決,只需要在Web Service調用前后加入日志代碼記錄調用時(shí)間即可實(shí)現。但在實(shí)際系統中,比如一個(gè)產(chǎn)品目錄的Web Service可能提供數十種查詢(xún)方法,而程序中很多組件都會(huì )依賴(lài)于該服務(wù)提供的查詢(xún)功能。如果在系統中所有的地方加入性能測定代碼,這個(gè)工作就變得非常 繁瑣和困難。我們需要用一種更加優(yōu)雅的解決方式,在增添新功能的同時(shí)并不影響系統代碼或結構。

4.2緩存

在項目實(shí)踐中,一個(gè)有效的改善Web Service系統性能的方法就是利用緩存來(lái)減少Web Service的重復調用。在具體實(shí)現中我們可以采用客戶(hù)端緩存和服務(wù)器端緩存等不同方式,他們具有不同的特點(diǎn)和適用范圍。在本文例子中,我們希望實(shí)現客 戶(hù)端緩存來(lái)提高系統性能。但由于Web Service業(yè)務(wù)邏輯的差別,我們希望能夠為特定的Web Service提供特定的緩存策略,而且這些策略應該是能夠被靈活配置的,它們不應于應用程序的邏輯代碼耦合在一起。

4.3故障恢復:

對于Web Service應用,系統的可用性也是一個(gè)需要考慮的重要問(wèn)題。在運行時(shí)由于網(wǎng)絡(luò )運行環(huán)境的復雜性和不確定性,用戶(hù)希望能夠對Web Service訪(fǎng)問(wèn)提供一定的故障恢復機制:比如重試或者訪(fǎng)問(wèn)備份服務(wù)(當系統在調用Web Service失敗后,使用備份Web Service的服務(wù)地址來(lái)繼續訪(fǎng)問(wèn))。這些故障恢復策略應該是可配置的,對應用邏輯透明的。





回頁(yè)首


5.使用AOP解決SOA應用中的Crosscutting Concern

通過(guò)對上邊一系列問(wèn)題的分析,讀者也許會(huì )發(fā)現這些問(wèn)題并不是Web Service訪(fǎng)問(wèn)的核心問(wèn)題,但會(huì )影響系統中許多不同的組件。而且其中一些問(wèn)題需要我們能夠靈活配置不同的實(shí)現策略,因此我們不應該將處理這些問(wèn)題的代碼與應用代碼混合。

下面我們將利用AOP(Aspect-Oriented Programming)提供的方法來(lái)解決上述的問(wèn)題。AOP是一種新興的方法學(xué),它最基本的概念就是關(guān)注隔離(Separation of Concern)。AOP提供了一系列的技術(shù)使得我們能夠從代碼中分離那些影響到許多系統模塊的crosscutting concerns,并將他們模塊化為Aspects。AOP的主要目的仍然是解耦,在分離關(guān)注點(diǎn)后,才能將關(guān)注點(diǎn)的變更控制一定范圍內,增加程序的靈活 性,才能使得關(guān)注能夠根據需求和環(huán)境作出隨時(shí)調整。

我們將利用Spring所提供的AOP功能支持來(lái)解決以上問(wèn)題。這里我們只簡(jiǎn)單地介紹涉及到的AOP基本概念以及實(shí)現,如果您希望更好地了解AOP的概念以及Spring AOP支持的細節請參見(jiàn)參考資料。

  • Joinpoint 是程序的運行點(diǎn)。在Spring AOP中,一個(gè)Joinpoint對應著(zhù)一個(gè)方法調用。
  • Advice 定義了AOP框架在特定的Joinpoint的處理邏輯。Spring AOP框架通過(guò)interceptor方式實(shí)現了advice,并且提供了多種advice類(lèi)型。其中最基本的"around advice"會(huì )在一個(gè)方法調用之前和之后被執行。

下面我們將利用Spring提供的MethodInterceptor來(lái)為Web Service調用實(shí)現我們的定義的處理邏輯。

5.1 PerformanceMonitorInterceptor

性能測量是AOP最簡(jiǎn)單的例子之一,我們可以直接利用Spring提供的實(shí)現在bean.xml中聲明我們的WebServicePerformanceMonitorInterceptor。

5.2 CacheInterceptor

為 了不引入緩存策略的復雜性,我們只提供了一個(gè)利用HashMap的簡(jiǎn)單實(shí)現:它利用 Web Service的調用參數列表作為HashMap鍵值。在Web Service調用之前,首先檢查緩存中是否擁有與現在參數列表相同的項,如果有則返回緩存的結果,否則調用Web Service并將<參數列表,結果>記錄在HashMap中。在實(shí)際應用中,您應該根據具體情況來(lái)選擇、構造適合Web Service的業(yè)務(wù)特性的Cache實(shí)現,也可以采用成熟的Cache實(shí)現。

在下面代碼實(shí)現中有一個(gè)生成Web Service調用主鍵的小技巧。因為Web Service引擎要求所有調用參數必須是可序列化的,所以我們可以利用Java提供的序列化功能來(lái)實(shí)現對象的克隆。如清單10所示:



清單10:SimpleCacheInterceptor的代碼示例
public class SimpleCacheInterceptor implements MethodInterceptor {
private Map cache = new HashMap();
private Object cloneObject(Object obj) throws Exception {
Object newObj = null;
if (obj != null) {
// 通過(guò)序列化/反序列化來(lái)克隆對象
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(obj);
out.flush();
out.close();
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bos.toByteArray()));
newObj = in.readObject();
}
return newObj;
}
//基于參數列表數組,生成用于HashMap的鍵值
public Object generateKey(Object[] args) throws Exception {
Object[] newArgs = (Object[]) cloneObject(args);
List key = Arrays.asList(newArgs);
return key;
}
//實(shí)現使用緩存技術(shù)的invoke方法
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object result = null;
Object data = null;
Object key = null;
try {
key = generateKey(methodInvocation.getArguments());
data = cache.get(key);
} catch (Exception ex) {
logger.error("Failed to find from the cache", ex);
}
if (data == null) {
//如果Cache中沒(méi)有緩存結果,調用服務(wù)執行生成用于HashMap的鍵值
result = methodInvocation.proceed();
try {
data = cloneObject(result);
cache.put(key, data);
} catch (Exception ex) {
logger.error("Failed to cache the result!", ex);
}
} else {
result = data;
}
return result;
}
}

5.3 FailoverInterceptor

下面代碼提供了一個(gè)基于服務(wù)備份切換的故障恢復實(shí)現,在運行時(shí),如果Interceptor檢測到服務(wù)調用由于網(wǎng)絡(luò )故障拋出異常時(shí),它將使用備份服務(wù)的端點(diǎn)地址并重新調用。如清單11所示:



清單 11: SimpleFailoverInterceptor的代碼示例
public class SimpleFailoverInterceptor implements MethodInterceptor {	…

//實(shí)現支持端點(diǎn)運行時(shí)切換的invoke方法
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object result = null;
try {
result = methodInvocation.proceed();
} catch (Throwable ex) {
if (isNetworkFailure(ex)) {
//切換服務(wù)端點(diǎn)地址
switchEndPointAddress((Stub) methodInvocation.getThis());
result = methodInvocation.proceed();
} else {
throw ex;
}
}
return result;
}
}

為了支持備份服務(wù)切換的功能,我們在WebServicePortProxyFactoryBean中為填加了配置參數"endpointAddress2",它會(huì )在創(chuàng )建的Web Service客戶(hù)端代理對象中記錄備份URL。

我們可以在CurrencyExchangeService加入下列參數來(lái)試驗SimpleFailoverInterceptor的功能。其中第 一個(gè)端點(diǎn)地址為一個(gè)錯誤的URL。在第一次調用服務(wù)時(shí),SimpleFailoverInterceptor會(huì )偵測到網(wǎng)絡(luò )故障的發(fā)生,并自動(dòng)切換使用第二 個(gè)端點(diǎn)地址繼續訪(fǎng)問(wèn)。如清單12所示:



清單12:配置文件種增加的屬性
		
<property name="endpointAddress">
<value>http://localhost/wrong_endpoint_address</value>
</property>
<property name="endpointAddress2">
<value>http://services.xmethods.net:80/soap</value>
</property>

5.4配置文件和運行結果

現在我們需要在Spring配置文件中,為所有interceptor添加定義,并描述如何為CurrencyExchangeService構建 AOP Proxy。需要指出的是,我們要在interceptorName列表中聲明interceptor鏈的調用順序,還要將原有 CurrencyExchangeManager引用的stub對象替換為新AOP Proxy。如清單13所示:



清單13:修改后的配置文件片段
<bean id="WebServicePerformanceMonitorInterceptor"
class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor">
<property name="prefix">
<value>Web Service </value>
</property>
<property name="suffix">
<value></value>
</property>
</bean>
<bean id="CacheInterceptor" class="test.ws.SimpleCacheInterceptor"/>
<bean id="FailoverInterceptor" class="test.ws.SimpleFailoverInterceptor"/>
<bean id="CurrencyExchangeProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>net.xmethods.www.sd.CurrencyExchangeService_wsdl.
CurrencyExchangePortType</value>
</property>
<property name="target">
<ref local="CurrencyExchangeService"/>
</property>
<property name="interceptorNames">
<list>
<value>WebServicePerformanceMonitorInterceptor</value>
<value>CacheInterceptor</value>
<value>FailoverInterceptor</value>
</list>
</property>
</bean>
<bean id="CurrencyExchangeManager"
class="test.ws.CurrencyExchangeManagerImpl">
<property name="stub">
<ref bean="CurrencyExchangeProxy"/>
</property>
</bean>

這里我們通過(guò)為AOP 的ProxyFactoryBean為 Web Service Stub創(chuàng )建了一個(gè)AOP代理,并且建立了一個(gè)Interceptor鏈。這樣在調用Web Service時(shí),Spring框架會(huì )依次調用Interceptor執行。實(shí)例執行的順序圖將如圖5所示:



圖5系統運行順序圖

5.5 Interceptor與JAX-RPC Handler的關(guān)系與區別

SOAP Message Handler是JAX-RPC為用戶(hù)自定義Web Service處理過(guò)程提供的一種擴展機制。在處理Web Service請求/響應過(guò)程中,Web Service 引擎會(huì )根據部署描述中的定義,按照一定的次序調用Handler的處理代碼。用戶(hù)編寫(xiě)的Handler實(shí)現可以截獲并修改Web Service消息和處理流程,從而實(shí)現對Web Service引擎處理行為的定制和增強。

比如,我們可以實(shí)現一個(gè)服務(wù)器端Handler,記錄Web Service在受到請求消息和發(fā)出響應消息之間的時(shí)間間隔來(lái)實(shí)現對服務(wù)器端業(yè)務(wù)性能的測定。而且我們只需在部署描述中增加Handler聲明即可,無(wú)需修改任何服務(wù)器端代碼。

從此可以看出,JAX-RPC Handler與我們在上文中所提供的AOP Interceptor都可以幫助我們的SOA應用程序實(shí)現關(guān)注分離(Separate Concern)的目標,在不改變應用代碼的同時(shí),增強或改變Web Service服務(wù)訪(fǎng)問(wèn)的功能。雖然我們可以利用它們實(shí)現一些類(lèi)似的功能,但它們具有著(zhù)不同的特點(diǎn)和適用范圍。

JAX-RPC Handler是Web Service引擎的擴展機制。如果我們需要實(shí)現對SOAP消息進(jìn)行的修改和處理,加入自定義的SOAP Header或對消息內容進(jìn)行加密,Handler是我們的最佳選擇。而AOP是針對對象級別的擴展機制,它更適合對應用層邏輯進(jìn)行操作。

比如,我們在上文展示的利用AOP實(shí)現的CacheInterceptor,它緩存的是Web Service調用參數和結果。而我們也可以通過(guò)JAX-RPC Handler實(shí)現一個(gè)面向SOAP消息的實(shí)現,它將緩存Web Service的請求消息和響應消息。這兩個(gè)實(shí)現相比,基于A(yíng)OP的實(shí)現更加簡(jiǎn)單、直觀(guān)、快速、對資源消耗也比較小。而面向SOAP消息的實(shí)現則更加靈 活,對于不采用RPC方式的Web Service訪(fǎng)問(wèn)也能提供支持。

所以在具體的實(shí)踐過(guò)程中,開(kāi)發(fā)人員應該根據具體的需求選擇合適的技術(shù),也可以將這兩種技術(shù)結合使用。





回頁(yè)首


6.總結

"分而治之"的方法是人們解決復雜問(wèn)題的一種常見(jiàn)做法。而IoC、AOP等技術(shù)都體現了這種思想。通過(guò)更好的切分程序邏輯,使得程序結構更加良好,更加富有彈性,易于變化。也使得開(kāi)發(fā)人員可以更加專(zhuān)注于業(yè)務(wù)邏輯本身,而將一部分其他邏輯交給容器和框架進(jìn)行處理。

在本文中,我們通過(guò)一個(gè)Web Service訪(fǎng)問(wèn)的實(shí)例,具體描述了SOA應用中所遇到的一系列具體問(wèn)題,并描述如何利用IoC和AOP等技術(shù)進(jìn)行代碼重構,構建更加結構良好、靈活的SOA應用。綜上所述,我們可以看到:

1使用IoC框架來(lái)實(shí)現對象的生命周期管理、配置管理和依賴(lài)管理,可以解除業(yè)務(wù)邏輯對服務(wù)調用的依賴(lài)關(guān)系;

2 使用AOP方法來(lái)解決Web Service調用中的crosscutting concerns,將為系統增加新的功能而不必更改應用程序。

3通過(guò)IoC和AOP來(lái)屏蔽Web Service訪(fǎng)問(wèn)的復雜性,使得開(kāi)發(fā)人員可以更加專(zhuān)注于業(yè)務(wù)邏輯本身,也使得系統更加穩定和富有彈性。 

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
從Spring實(shí)例入手談SCA Component的創(chuàng )建和調用
使用Spring框架的好處(轉帖)
編寫(xiě)一個(gè)Web service客戶(hù)端
使用 Hibernate 和 Spring AOP 構建泛型類(lèi)型安全的 DAO
使用Axis開(kāi)發(fā)Web Service程序
9.6.1 可用的TargetSource實(shí)現類(lèi)(2)(雙數據源交換)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久