• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

使用IoC和AOP重构SOA应用(1)

发布: 2007-6-13 19:50 | 作者: 易立 赵勇 | 来源: | 查看: 52次 | 进入软件测试论坛讨论

领测软件测试网

1.引言

SOA是一种构造分布式系统的方法,它将业务应用功能以服务的形式提供出来,以便更好的复用、组装和与外部系统集成,从而降低开发成本,提高开发效率。SOA的目标是为企业构建一个灵活,可扩展的IT基础架构来更好地支持随需应变的商务应用。

随着SOA技术和产品的不断成熟,现在越来越多的用户开始了解并认同SOA的理念,但对SOA项目的实施还缺乏信心。其主要原因是:SOA应用开发还相对比较复杂。

一年多来,本文作者所在的部门已经从事了许多国内外的SOA项目的实施和支持工作,积累了许多SOA应用开发经验。我们希望能够通过一系列的文章与读者分享这些想法,帮助您更好地构建SOA应用。

本文将从Web Service调用入手,在解决一系列具体问题的过程中,使用IoC (Inversion of Control) 和AOP (Aspect- Oriented Programming) 等方法重构Web Service的访问代码,使得业务逻辑与Web Service访问解耦,为您提供一个更加灵活和易于扩展的访问模式。

Spring是一个流行的轻量级容器,对IoC和AOP提供了良好的支持。本文为您提供了一个基于Spring的实现供您下载学习。示例代码工程使用Eclipse3.1/3.02和JDK1.4开发, 您还需要Spring 1.2.5和Axis1.3提供的支持。源码下载。

2.Web Service调用

Web Service是目前实现SOA应用的一项基本的,适用的技术,它为服务的访问提供了一个被广泛接受的开放标准。为了便于说明问题,我们将使用XMethods 网站(http://www.xmethods.net/)发布的货币兑换服务作为示例。并针对JAX-RPC 1.1,说明如何编写Web Service 的调用代码。

2.1 示例说明

http://xmethods.net 作为最早推出Web Service实际示例的网站,提供了很多优秀的Web Service 样例。其中有一个汇率计算服务,可以返回两个国家之间的货币兑换比例。获取该服务的详细信息,请参考该服务的服务描述文档(获取WSDL 文档) 。在此就不具体解析该服务描述文档了。读者可以从WSDL2Java生成的接口中了解该服务的用法:

public interface CurrencyExchangePortType extends java.rmi.Remote {

public float getRate(String country1, String country2) throws java.rmi.RemoteException;

}

2.2 客户端调用方法

JAX-RPC作为Java平台的RPC服务调用标准接口,为Web Service客户端调用提供了3种方法,分别是DII,动态代理,和静态Stub。 DII(Dynamic Invocation Interface)采用直接调用方式,可以在程序中设置诸多的调用属性,使用较为灵活,但是调用过程却相对繁琐复杂,易造成代码膨胀且可重用性低,每次调用不同的Web Service都要重复进行大量编码。

JAX-RPC中动态代理(Dynamic Proxy)的方法实现对Web Service的动态调用,可以在运行时根据用户定义的Client端接口创建适配对象。从而避免了直接操作底层的接口,减少了客户端的冗余,屏蔽了调用相关的复杂性。

使用静态Stub和Service Locator是目前最常用的调用方式。JAX-RPC使用静态的Stub方式包装对底层接口的调用,从而提供一种更为简便的调用方式。使用该方式需要利用支持环境(比如Axis)所提供的工具根据WSDL预生成Web Service客户端的实现代码。因此如果服务的WSDL发生变化,就必须重新生成新的客户端代码并进行重新部署。

为了更详细的了解静态Stub的调用方式,您可以将示例代码的WebServiceClient.jar导入到您现有Eclipse工作区之中。

客户端生成代码包括如下4个类:如图 1 所示:

图 1: 客户端代码类图

在上图中包括的几个类中:

  • CurrencyExchangePortType:服务端点接口,定义了Web Service的方法签名。
  • CurrencyExchangeService:Service接口,定义了获取服务端点接口的方法。
  • CurrencyExchangeServiceLocator:ServiceLocator类,实现了Service接口。
  • CurrencyExchangeBindingStub: Stub实现类,实现了服务端点接口,封装了对Web Service访问的底层逻辑。

使用Stub调用Web Service的过程也非常简单,读者可以参考清单 1:

清单 1:Web Service 调用代码示例

try {

//创建ServiceLocator

CurrencyExchangeServiceLocator locator = new

CurrencyExchangeServiceLocator();

//设定端点地址

URL endPointAddress = new URL("http://services.xmethods.net:80/soap");

//创建Stub实例

CurrencyExchangePortType stub =

locator.getCurrencyExchangePort(endPointAddress);

//设定超时为120秒

((CurrencyExchangeBindingStub)stub).setTimeout(120000);

//调用Web Service计算人民币与美元的汇率

float newPrice = stub.getRate("China", "USA") * 100;

} catch (MalformedURLException mex) {

//...

} catch (ServiceException sex) {

//...

} catch (RemoteException rex) {

//...

}

3.重构Web Service调用代码

3.1 实例代码中的"坏味道"

上面的基于Service Locator的Web Service访问代码虽然简单但暴露出以下几个问题:

1.访问Web Service所需的配置代码被嵌入应用逻辑之中

在Web Service调用中,我们需要设定一系列必要的参数。比如:服务端点地址、用户名/密码、超时设定等等。这些参数在开发和运行环境中都有可能发生变化。我们必须提供一种机制:在环境变化时,不必修改源代码就可以改变Web Service的访问配置。

2 客户端代码与Web Service访问代码绑定

在上面的代码中,业务逻辑与Web Service的Stub创建和配置代码绑定在一起。这也不是一种良好的编程方式。客户端代码只应关心服务的接口,而不应关心服务的实现和访问细节。比如,我们既可以通过Web Service的方式访问远程服务,也可以通过EJB的方式进行访问。访问方式对业务逻辑应该是透明的。

这种分离客户端代码与服务访问代码的方式也有利于测试。这样在开发过程中,负责集成的程序员就可能在远程服务还未完全实现的情况下,基于服务接口编写集成代码,并通过编写POJO(Plain Old Java Object)构建伪服务实现来进行单元测试和模拟运行。这种开发方式对于保证分布式系统代码质量具有重要意义。

因此,为了解决上面的问题我们需要:

1、将Web Service访问的配置管理与代码分离;

2、解除客户端代码与远程服务之间的依赖关系;

3.2 利用IoC模式进行重构代码

我们先介绍在Core J2EE Patterns一书中提到的一种业务层模式:Business Delegate。它所要解决的问题是屏蔽远程服务访问的复杂性。它的主要思想就是将Business Delegate作为远程服务的客户端抽象,隐藏服务访问细节。Business Delegate还可以封装并改变服务调用过程,比如将远程服务调用抛出的异常(例如RemoteException)转换为应用级别的异常类型。

其类图如图 2 所示:

图 2:Business Delegate 模式的类图图解

Business Delegate模式实现很好地实现了客户端与远程访问代码的解耦,但它并不关注Delegate与远程服务之间的解耦。为了更好解决Business Delegate和远程服务之间的依赖关系,并更好地进行配置管理,我们可以用IoC模式来加以解决。

IoC(Inversion of Contro)l意为控制反转,其背后的概念常被表述为"好莱坞法则":"Don't call me, I'll call you." IoC将一部分责任从应用代码交给framework(或者控制器)来做。通过IoC可以实现接口和具体实现的高度分离,降低对象之间的耦合程度。Spring是一个非常流行的IoC容器,它通过配置文件来定义对象的生命周期和依赖关系,并提供了良好的配置管理能力。

现在我们来重构我们的Web Service应用程序,我们首先为Business Delegate定义一个接口类型,它提供了一个应用级组件接口,所有客户端都应通过它来执行汇率计算,而不必关心实现细节,如清单 2 所示:

清单 2:接口定义的代码示例

Public interface CurrencyExchangeManager {

//货币兑换计算

//新价格 = 汇率 * 价格

public float calculate(String country1, String country2, float price)

throws CurrencyExchangeException;

}

Business Delegate的实现非常简单,主要工作是包装汇率计算 Web Service的调用,如清单 3 所示。

清单 3:Business Delegate的代码示例

public class CurrencyExchangeManagerImpl implements CurrencyExchangeManager {

//服务实例

private CurrencyExchangePortType stub;

//获取服务实例

public CurrencyExchangePortType getStub() {

return stub;

}

//设定服务实例

public void setStub(CurrencyExchangePortType stub) {

this.stub = stub;

}

//实现货币兑换

public float calculate(String country1, String country2, float price)

throws CurrencyExchangeException {

try {

//通过Stub调用WebService

float rate = stub.getRate(country1, country2);

return rate * price;

} catch (RemoteException rex) {

throw new CurrencyExchangeException(

"Failed to get exchange rate!", rex);

}

}

}


共3页: 1 [2] [3] 下一页

延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/

41/41234>

关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备10010545号-5
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网