REST会是SOA的未来吗?

好像无论我们到哪儿都能听到这样的说法:REST将会是SOA的未来。很多刊物也将REST和SOAP与WS*[1]标准进行比较,但这些比较看起来都太过简单了。近来出现了两种较为主流的方法——本真REST(true REST)以及将REST作为面向服务的技术方法(又称REST Web服务[2])。本文讨论的重点为:是否其中一种方法能够改进SOA实现。

面向SOA的本真REST

本真REST当然是对面向资源架构的一种实现,而并非一种纯粹的技术决策。所以当讨论本真REST时,真正应该讨论的问题是:其基础支撑——面向资源的架构(ROA)——是否真的适合作为你的SOA实现。

为正确评估该问题,让我们首先回想一下SOA的架构风格,它是基于企业业务架构的功能性分解,并且引入了两个高层次的抽象:企业业务服务和业务流程。企业业务服务代表的是现有IT能力(和企业的业务功能相一致)。业务流程编排业务服务,并定义业务的整体功能。

而REST是一组被称之为面向资源架构(ROA)的架构准则。ROA构建在资源这一概念之上;每个资源都是一个能够直接访问的分布式组件,可通过一个标准的、通用的接口来处理。所以,面向资源的架构(ROA)其最根本的还是一种基于资源的分解[3]

为了评估本真REST是否适用于面向SOA的实现,我们真正需要回答的问题是,“服务和资源之间到底是什么关系?”

服务 vs. 资源

何为服务?

在最简单的情况下,服务可以被定义为一个自包含、独立开发、可部署、可管理和可维护的软件实现,它从整体上为企业提供特定的与业务相关的功能,并且在设计上是“可集成的”。“服务”可以通过动词(verb)来定义(例如,“验证客户信用积分”,这描述了服务实现的业务功能)。

服务并不是某个编程结构或一组APIs,而是一个用于实现企业解决方案的架构(设计单元、实现以及维护)和部署构件。服务接口(尤其对某个给定的服 务而言)定义服务功能,并且可由多种方式实现。存在两种基本的定义服务接口的方法——RPC风格和消息(messaging)风格,RPC风格实现使用服 务调用语义并且通过服务接口中的一组参数来定义。而消息风格的服务接口被有效地固定(本质上只需要进行“执行”操作)使用XML文档作为输入和输出(这和 GoF设计模式非常相似)。在这种情况下,服务语义是由输入和输出消息的语义来确定[4]

过去,服务通常被定义为一组方法的集合,但正如参考文献[2]中解释的那样,这些方法彼此相互独立[5],但作为整体它们共享同一个命名空间,这样简化了对服务的管理。

何为资源?

在最简单的情况下,资源可以被定义为一个可直接访问的、独立开发的、可部署的、可管理的和可维护的软件构件,它支持特定的数据。资源可以通过名词(noun)来定义,比如“医生的预约”就描述了资源提供的数据。某一资源也可以和其他资源相关联并为它们提供引用(链接)。实际上,一个资源就类似于一个对象[6],不过它是带有预定义(CRUD)接口语义的对象。

REST中的语义基于HTTP操作集,如下所示[5]

  • createResource——创建一个新的资源(以及相应的唯一标示)– PUT
  • getResourceRepresentation——获取资源信息– GET
  • deleteResource ——删除资源(可选地包括相关联的资源)– DELETE(只是引用的资源),POST(当需要删除相关联的资源时使用)
  • modifyResource——更改资源— POST
  • getMetaInforatmion——取得资源元数据信息—HEAD

资源通过两部分定义:资源URL和资源所提供的所有操作上定义的输入/输出参数[7]。这和服务不同,服务的方法之间是完全独立,并且能够以独立端点(endpoints)的方式部署,而资源上的方法遵循OO语义,这意味着所有的方法(除createResource以外)都必须依附于底层的某个资源(同一个URL)。

资源和服务之间的根本差异

基于上述对资源和服务的定义,凭直觉它们显然是不同的。我们先继续深究这些差别,然后再讨论它们是如何对最终架构产生影响的。

正如文献[6]中描述的:

REST不仅不是面向服务的,相反,面向服务和REST风马牛不相及

文献[7]中进一步阐明了二者之间的区别:

如果把WS-*比作是互联网世界的RPC,那么REST就是互联网世界的数据库管理系统(DBMS)……传统的 基于SOA的集成表现了不同软件构件之间通过各种过程或方法进行交互。REST有效地将每个软件构件看作一组数据库表,而这些构件之间使用SELECT, INSERT, UPDATE和DELETE来通信。(或如你所想的使用GET, PUT, POST, DELETE)。那业务逻辑放在哪里呢?在存储过程中?不太对,其实在触发器中。

这里我们用J2EE打个稍微不太恰当的比方。我们把服务想象成无状态会话bean,而资源想象成实体bean。

服务(或会话beans)作为控制器控制执行所需的操作,不管底层是哪个资源。打个比方,某个支出账户服务可能会用到账户ID、支出金额和支出所需账户。这样的服务可以支出任何现有账户。

资源(或实体bean)充当数据访问机制,其面对给定数据类型的某一实例。比如,为了从某一账户支出,需要先找到这一账户相关的信息,然后才能更新它,从而向所需账户进行支出。另外提醒一下,与能实现任意所需的方法的实体bean不同的是,一个REST资源只有一个更改资源的方法。这意味着真实的业务操作——支出——只能编码成消息请求的一部分。

区别引出的结论

综上所述,不可能使用本真REST来构建SOA系统。构建系统可以,但一定不是SOA。两者都可以从与业务一致的分解入手,但是由于各自使用截然不同的分解方法,它们最终得到的也是基于不同组件和连接器的完全不同的架构风格[8]

仅仅因为它们都试图解决同一个问题——业务与IT对齐,并且都基于业务驱动的分解,并不能表明最终的架构风格也是一样的。

另一个问题在于能否可能使用本真REST来构建一个完整的系统。鉴于上述理由,这个问题等价于能否可能只使用数据库或实体bean来构建一个完整的 系统。当然你可以了,但是需要以存储过程(重写方法的本意)的方式增加处理代码,或者触发器(完成基于数据变化的后置处理)。这同样适用于本真REST实 现—你只有通过改变modifyResource方法的本意(通常使用命令行模式)来实现不止数据更新这个方法。

因此,某个基于REST的实现和本真REST是大相径庭的;一般来说其包含了至少一些REST Web服务的元素。那么REST Web服务是什么呢?

REST Web服务

REST Web服务方法是指单纯使用REST技术作为通信手段来构建SOA的一种方法。在这种情况下,服务由SOA风格的分解来定义,而基于REST的Web服务[9]作为通信。

虽然一般也被称为REST,这种方法其实和本真REST没有一点关系,倒是和POX(plain old XML over HTTP)很类似,不过与POX不同的是,它不仅支持XML,还支持其他数据类型,比如JSON(JavaScript Object Notation)、ATOM、二进制数据块。而且,它不像POX那样通常只基于GET和PUT,它基于更多的HTTP方法。

归功于Web的优势和Ajax技术的遍地开花,使用JSON逐渐变成主流的方法;大部分流行的浏览器都内置对JSON支持。由于在 JavaScript中处理XML(尤其是带有很多命名空间)并不是一件容易的事,所以,Web实现使用基于JSON的REST Web服务要容易的多。面向Web交互的REST Web服务的扩增导致了这些技术的日益流行和广泛传播。

真正的差异是什么?

描述SOAP和REST区别的出版刊物通常会指出如下REST Web服务的优点,比如[11]

  • 轻量级——无需太多额外的XML标记
  • 人工可读的结果集
  • 易于构建——无需工具支持

虽然这些区别很重要(我随后会再详细讨论),但是SOAP和REST最主要的区别在于REST是直接实现于HTTP协议之上,而SOAP引人了一个 抽象层(SOAP消息传递),这可以在任何传输协议之上实现。标准化SOAP绑定目前存在于HTTP、SMTP和JMS之上,而非标准化绑定已经在其他一 些协议解决方案实现了。这层额外的抽象层(提供协议和基于SOAP实现之间的解耦)是造成SOAP和REST Web服务区别的根源。

对于这一抽象层的看法很大程度上取决于不同的人。REST阵营认为它是过度设计的产物,并声称没有提供任何实际价值。他们声称HTTP已经提供了服 务交互实现必需的所有特点。而SOAP阵营,从另一方面,争辩道HTTP并不是服务交互(尤其在企业内部)通常所需的唯一协议,而设计一个方便的、可扩展[10]的抽象层对构建健壮的、功能丰富的服务交互是很有必要的。

虽然两种观点都有其可取之处,但我认为把SOA实现限制到单一协议,即HTTP,实际操作起来不太可行。诚然,HTTP是无处不在,并且其使用方法一般也无需投资额外的基础设施,但是HTTP是不可靠的(HTTP-R没有广泛被采用)、同步的(产生了瞬时的耦合)[11]、而且也没有事务语义等等。

再者,就算认为HTTP是在实现中使用的唯一协议,也可以非常方便的利用SOAP信封把业务信息(SOAP 消息体)和基础设施信息或附加信息(SOAP 消息头)从SOAP消息中隔离。总的来说,如果你本来的实现并不需要任何基础设施或附加数据,整个SOAP信封的开销是很少的——只需两个标签,而且对必 要时添加数据提供了明确定义的方法。

所以,从各个方面来看,以数据信封的方式将业务信息和基础设施关注分离是很强大的模式,甚至REST Web服务实现也常常使用这种方法。至于是否使用标准的SOAP还是定制化信封[12]模式要根据具体实现而定。

其他关键不同点

我们花点时间来讨论一下其他一些常常被发表刊物引用的关于SOAP和REST Web服务的不同点。

简单化

一个普遍的观点是REST要比SOAP简单得多。照这个观点,REST简单的根源基于一个事实:REST不需要WSDL或任何接口定义。至少可以认为这种论调有点天真。无论哪种用于服务消费者和提供者之间通信的技术,都必须在语法和其消息交互(接口)[13]的语义上达成一致。这意味着就REST而言,下面两个方法有一个是可能的:

  • 以文本方式定义一个接口,并基于接口文档描述中的通用接口定义来“手工地”编写数据的编码/解码。虽然这种方法常被REST拥趸所推崇, 其接口包含的元素很少超过10到15个,但这不是典型的粗粒度REST服务。而且,这种方法很容易出错,所以,大部分可行的REST框架都遗弃该方法而使 用下面的方法。
  • 在XSD的层次定义接口,基于流行框架(比如,面向XML的JAXB或Castor,面向JSON负载的Jackson)产生数据的编码 /解码。这种方法效果上就是WSDL的简约版,并且需要的工作量和基于SOAP实现差不多一样。事实上,完全相同的方法经常被用于基于SOAP的实现,设 计一个单独接口和服务执行的命令模式。WSDL2.0 和/或 WADL for REST就是对该方法的扩展。

另一个SOAP常常被抱怨的就是复杂的WS*标准集。虽然不存在一个单独的规范来罗列这些关键的WS*标准集以及其彼此的关系,但对大部分服务交互用例还是存在一个标准的。就算如此,选择一个适当的WS*标准和其用法可能也需要一些额外理解和实现时间,但是:

在REST和SOA之战中争论简单化还是标准化是荒唐的,因为没有标准支持的简单只能有害于成本和应用的可管理性。

所以,除了那些简单到极点的例子之外,如“温度转换器”,REST并不比SOAP简单多少。

轻量级

另一个众多REST拥趸宣扬REST是SOAP的一种取代的原因是,实际上的REST请求和响应消息都较短。这主要基于两个原因:

  • SOAP需要一层XML包装器来包装所有的请求和响应消息,这会增加消息的大小。这话没错,但重点不是包装器增加了多少字节,而是它创建 在整个负载中的比例。因为包装器的大小是固定的,其所占比例随着消息的不断变大而变小,最终可以忽略不计。考虑到一般服务都是相当粗粒度的,请求和回复消 息的大小也是相当大的,所以SOAP信封的负载不太会成为大问题。
  • SOAP是基于XML的消息传输,而XML使用冗余的编码。REST,在这方面,提供了更轻量级的消息传输替代方案——JSON[14]。这话也对,但利用消息传输优化机制(MTOM),大部分SOAP框架都支持,可以把消息拆分成多个小的基于XML的SOAP信封/头/体部分,而附加的包含消息内容的部分可以编码为任何MIME类型,包括JSON和二进制流等。

虽然理论上讲,REST要比SOAP轻量级,但实际上,利用一些高级SOAP设计技术,真正使用中的SOAP和REST消息大小的差别是很小的。

易于构建 – 无需工具支持

因为REST基于HTTP,其拥趸认为,我们可以使用熟稔的技术,比如Java servlet API和Java HTTP支持来编写REST服务的实现端和客户端,而无需任何特定工具的帮助。这可以说是对的,但前提是你想要“手工”实现构建输入/输出消息和数据编 组。SOAP Web服务也可以实现同样的工作。然而,大家很少希望编写这种样例代码,结果还是会使用工具,SOAP和REST都是。

结论

REST既适用于使用ROA(本真REST方法)的系统设计,也适用于使用REST技术(REST Web服务)的SOA设计实现。虽然两种方法都有其优势,但都没有改变最难的部分——定义和企业业务模型一致的业务服务/资源。有些情况的确两种都适合, 但归根到底这完全是两种不同的风格。

关于作者

Boris Lublinsky是NAVTEQ公司的首席架构师,在这家公司中他的工作是为大型数据管理及处理、SOA定义架构愿 景,并且实施各种NAVTEQ的项目。他还是InfoQ的SOA编辑, OASIS的SOA RA工作组的参与者。Boris是一位作者,还经常发表演讲,他最新的一本书是《Applied SOA》

致谢

我要谢谢我NAVTEQ的同事,尤其是Jeffrey Herr在我撰写这篇文章时提供的帮助。也要感谢Stefan Tilkov和Kevin T. Smith提供的有趣反馈(多数是负面的),这些反馈有助于文章的改进。

参考

  1. Cesare Pautasso,Olaf Zimmermann,Frank Leymann著《RESTful Web Services vs. “Big” Web Services: Making the Right Architectural Decision》
  2. Boris Lublinsky著《Defining SOA as an architectural style
  3.  面向资源的架构
  4. Martin Fowler Richardson著《Maturity Model: steps toward the glory of REST
  5. 面向资源的架构与REST
  6. Dhananjay Nene的博文“Service oriented REST architecture is an oxymoron
  7. Dhananjay Nene,“REST is the DBMS of the Internet ”。
  8. Dhananjay Nene,“Musings on REST
  9. J?rgen Thelin,“A Comparison of Service-oriented, Resource-oriented, and Object-oriented Architecture Styles
  10. Richard Hubert著《Convergent Architecture: Building Model Driven J2EE Systems with UML》,Wiley,2011,ISBN:0471105600
  11. Arun Gandhi, “SOAP vs. REST – The Best WebService”。
  12. 请参见链接
  13. Lawrence Mandel,“Describe REST Web services with WSDL 2.0
  14. Web应用描述语言
  15. Stefan Tilkov 访谈Sanjiva Weerawarana,“Debunking REST/WS-* Myths
  16. Lori MacVittie,“SOAP vs REST: The war between simplicity and standards
  17. 请参见链接
  18. Mark Little,“A Comparison of JAX-RS Implementations”。

[1]看这里,文中有个很好的比喻。

[2]这里我使用的这个词语,从技术上其毫无意义,也不是指REST,但在业界被广泛使用,而有很多人也认为它就是REST。

[3]按照定义,资源可以是任何应该被直接呈现和访问的组件。

[4]这类服务常用的一种实现是基于“命令模式”。一个输入文档定义命令本身和用于执行命令的数据。

[5]方法独立源自于这样一个事实:不同的方法可以执行同一数据——这里指的是无论是否被服务暴露都存在的企业数据,而不是在OO中的针对特定数据的某对象实例。

[6]例如,在文献[4]中对OO和REST做了直接类比。

[7]许多REST倡导者声称后者是没有必要的。我们在文章后面会再回到这个问题上。

[8]架构风格就像面向于不同软件系统之间结构和连接的“设计模式”。文献[10]提供了关于架构风格的一个比较完整的定义,“架构风格是指一组有相同原则和属性的架构”

[9]另一个在业界被普遍乱用的名称——根据定义,Web服务就是SOAP消息。

[10]所有的WS*实现都重度依赖SOAP,尤其是SOAP头。

[11]你总是可以在HTTP上实现异步消息机制,但是需要额外的抽象层,比如SOAP就在其上使用了WS-Addressing。

[12]许多REST倡导者认为HTTP已经有了一组标准的消息头,因此SOAP消息头完全没有必要。这里的问题在于一组预定义好的HTTP头固然有其良好定义的语义,但任何应用特定数据必需一个自定义HTTP消息头,这和自定义SOAP消息头的复杂度相同。

[13]一个有趣例子是,在很多JAX-RS实现中客户端API,其接口往往是一个java接口——许多对多语言的支持。

[14]简单通常意味着高价——所以,要试图通过无需手动编码对象类型而用JSON消息实现多态

查看英文原文:Is REST the future for SOA?


感谢马国耀对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。

This entry was posted in Achitecture, SOA. Bookmark the permalink.

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s