技术文章_理解耦合

耦合是一个含义不明确的术语,常被人撇到一边不管,很少有人去想它的含义及其对软件系统的影响。几乎差不多所有可伸缩性的场合,耦合都会起作用。而且正如在Mastering EJB 2.0可从www.theserverside.com下载)一书的“Clustering一章中详细论述的可伸缩性是一个在计算机科学中没有什么基础的术语。耦合应该被提升到与详细审查(scrutiny)一样的地位。

耦合可用的方式有很多种:紧耦合、松耦合、去耦等等。这些术语真正的意思是什么呢?在谈到我们开发的软件时,我们会正确地使用它们吗?

面向消息的中间件(message-oriented middlewareMOM)的制造商是耦合这一术语最广泛的使用者(也许是滥用者?)。多年来,他们一直在吹嘘合并MOM体系结构最大的好处就是能把一个系统从另一个系统中解除耦合。但是真的是这样么?幸运的是,耦合是一个有着具体定义的实际术语。
    如果系统的依赖性需要通过更新系统来支持依赖性所发生的变化时,那么系统就是耦合的。

去耦系统是指这样一种系统:以任何方式更新系统时都不会影响系统的操作。松耦合和紧耦合是两个意义不太明确的术语,因为它们用来描述系统及其依赖性之间的耦合“程度”。由于每个系统都以不同的方式来进行耦合,确定耦合程度的方式也往往会因人而宜。

让我们看一下这种定义是如何应用于MOM系统的。我们假定有两个应用程序A1A2。这些应用程序使用点对点域模型来通过队列进行联系。我主张A1A2之间是去耦的,但是整个系统是耦合的。为什么要这样呢?因为整个系统不仅仅只有A1A2,通过队列建立联系的是那些应用程序,包括队列和消息。在大多数的MOM系统中,产生和消费消息到队列中的应用程序都通过一种预定义消息类型来工作。如果消息格式必须更新的话,那么作为生产者和消费者的应用程序也必须进行更新。这就意味着即使应用程序本身是去耦的,但系统也是耦合的。

Web服务是去耦的?

Web服务供应商吹嘘其优点之一就是Web服务是去耦的。事实并不是这样的。Web服务系统在最基础的层面上,通过使用单个队列,利用两个应用程序来并行一个MOM系统。在一个简单的Web服务场景中,有两个端点(应用程序)使用SOAP进行通信。SOAP协议好比是MOM队列,而SOAP请求就好比是消息。这就意味着Web服务端点和MOM系统具有同样的消息格式。

如果包含在SOAP请求中的XML格式发生改变,那么产生和消费这些请求的端点也必须要改变。这就产生了耦合的问题,这个问题是所有Web服务系统固有的。

情况其实更糟。XML用于SOAP请求的消息格式是因为它是抽象的、灵活的、可用于描述许多不同的事物。但是,Web服务端点总是用一种编程语言来实现,比如Java。所有Web服务基础设施都必须提供一种机制来“绑定”XML(包含在SOAP请求中)到端点实现语言,反之亦然。在基于JavaWeb服务实现中,SOAP解析基础结构必须提供一种XML->JavaJava->XML的绑定机制,以便将消息内容转换成Java参数,反之亦然。

这种XML和语言的绑定就产生了很多MOM系统无法解决的额外的耦合问题。许多MOM系统都对用于实现生产者和消费者端点的编程语言做了假定。对于一个纯粹的JMS系统,众所周知,端点是用Java语言实现的。这就使得MOM供应商将消息格式优化为支持Java,从而在后续减少和消除消息语言绑定的需要。对于Web服务就没有这种情况,因为语言绑定问题将一直存在。

因此,在管道层面上还存在争议。Web服务与现有的MOM系统相比,存在更大的耦合问题需要解决。在格式层面上,MOM系统具有更大的耦合问题,因为它们无法利用自我描述的消息格式,以便将界面从实现中分离出来。


解决Web服务的耦合问题

作为BEA WebLogic Workshop框架的一部分,BEA引入了一种新技术,并且相信有助于消除Web服务的耦合问题。这种技术称为XMAP,它能够完成两件事:

1.
消除XML和语言的绑定问题。

2.
解除Web服务消息和特定实现之间的耦合,这样两者就都能够单独实现。

作为XMAP技术如何工作的简单实例,让我们介绍一下由WebLogic Workshop提供的InputMapMultiple示例。假定您已经建立了一个Web服务,但是XML消息格式是预先确定的。这是一种常见情况,就像B2B网络已经有了预先确定的消息格式用于消息交换一样,您必须遵循它。XMAP技术允许您使用自己创建的实现程序和语言界面来建立Web服务,然后XML中映射成特定语言。

我们假定XML的内容如下:

<order>

<item>

<name>Oranges</name>

<amount>4</amount>

<price>2.0</price>

</item>

<item>

<name>Apples</name>

<amount>12</amount>

<price>3.6</price>

</item>

<item>

<name>Pears</name>

<amount>6</amount>

  <price>6.8</price>

</item>

<item>

<name>Tangerines</name>

<amount>13</amount>

<price>6.31</price>

</item>
</order>
正如您所看到的<order>元素可以有一个或多个<item>元素。现在作为Web服务开发人员,您想要创建适合您需要的(而非XML需要的)Java接口。所以,经过一番思考之后,您想要定义调用这一消息的实现方法,如下所示:

public float getTotalPrice(String [] nameArr,

int [] amountArr,

float [] priceArr)
我们希望每一参数的[0]数组元素能够填入第一个<item>结构的匹配元素的值。希望每一参数的[1]数组元素能够填入第二个<item>结构的匹配元素的值。依此类推。


进入XMAP
    XMAP允许我们执行这种映射关系。一个XMAP代码片断就是一个包含了一些扩展的XML结构。XML结构是一种消息格式,它可以在线传输和消费。如果消息格式是预先确定的,并且您已经知道了这种格式,那么您所创建的XMAP结构只需要模仿预先确定的格式即可。如果没有预先确定的格式,那您所创建的XMAP结构就应该成为Web服务所需要的XML消息格式。我们本例中的XMAP是:

<order>

<item xm:multiple="String name in nameArr, int amount in amountArr, float price in
priceArr">

<name>{name}</name>

<amount>{amount}</amount>

<price>{price}</price>

</item>
</order>
注意,XML格式和我们的XML片断几乎是一样的。细微差异在于有一个xm:multiple属性作为XMAP的扩展,并且一些参数的值用花括号{}括住了。XMAL有许多扩展,这些扩展在WebLogic Workshop文档中有完整的记录。
    XMAP中,任何一个用花括号括住的值,比如{name},表明在XML消息中该元素出现的值必须要插入到带有相同名字的语言参数中去。这表明<name>{name}</name>结构将会有值,这个值出现在插入到名为“name ”的Java参数的元素之间。但是,如果您注意了我们的方法的话,就会发现并没有一个叫做“name”的参数,我们使用一个数组来代替。
    xm:multiple属性是XMAP处理重复的XML结构的方法。属性的String值是一条命令,告诉XMAP解析器插入什么值到哪个数组中。例如,XMAP命令告诉解析器将{name}的值作为一个数组元素插入到nameArr数组中,nameArr数组是Java方法的一个参数。使用这一语法,XMAP解析器能够正确地填入数组的所有值。
    XMAP异常健壮。事实上,有一种名为Xscript的技术,它是ECMAScript的扩展。ECMAScript允许您在XMAP中应用逻辑结构,这样在绑定发生时就能够做出决定,反之亦然。另外,XMAP可应用到传入参数和传出参量中,这样就可以为不同的场景创建不同的XMAP


结束语
    那么,耦合问题消除了么?还没有完全消除,但它提供了很大的帮助。您的Web服务将仍然与XMAP耦合在一起,但最大的成绩是,您的Web服务和XML消息能够彼此解除耦合。XMAP的好处还在于它不仅仅适用于Java语言。Microsoft也用它从Web服务中解除C#应用程序的耦合。这就铺平了XMAP的采纳之路,使其为更多的Web服务社区所采纳,而不仅仅局限于Java社区。

作者简介
 Tyler Jewell是BEA的技术传播先驱。他还是《Java Web Services》一书的作者,《Mastering Enterprise JavaBeans 2.0》和《Professional Java Server Programming (J2EE 1.3)》的作者之一。J2EE和Web服务这两方面的Web题材的书他都写过。
华纬教育网www.hwjy.net.cn提供IT、外语学习、管理咨询类社区