`
阿尔萨斯
  • 浏览: 4198437 次
社区版块
存档分类
最新评论

使用 XML 实现 REST 式的 SOA

 
阅读更多

Adriaan de Jonge (adriaandejonge@gmail.com), 资深 Java 软件工程师, SDB Java

2008 年 3 月 06 日

面向服务体系结构常常意味着大型企业所用的重型技术。SOA 体系结构模式的优点也适用于比较小的环境。在采用 SOA 原理时,不必承担大型环境所需的所有开销。可以使用 REST 这样的轻量型技术实现 SOA。本文讲解实现的方法。

什么是 SOA?

如 果公司有大量应用程序,这些程序供不同部门的承担不同责任的职员使用,那么就适合使用面向服务体系结构(Service Oriented Architecture,SOA)。这些应用程序可以共享功能,但是功能的组合、用户界面细节和易用性需求是不同的。与许多企业体系结构一样,SOA 也采用一个多层模型,但是它不只如此。在服务器中,功能分散在单独的服务上。一个客户机可以使用其中的一个或多个服务,而一个服务也可以由许多客户机使 用。由此形成了一个松散耦合的体系结构,这大大提高了现有软件的可重用性。

常用的重型实现

常用缩写词
  • API:应用程序编程接口(Application program interface)
  • IT:信息技术(Information technology)
  • XML:可扩展标记语言(Extensible Markup Language)

SOA 尤其适合大公司,大公司往往有数百个应用程序,应用程序之间缺少良好的集成,所以公司需要清理 IT 基础结构。SOA 是一种已经证明有效的实践,对于大型环境尤其有效。采用 SOA 的公司可以把遗留的应用程序转换为服务,并把服务集成为现代应用程序的后端。可以使用中间件技术对服务进行组合,并对服务中的特定功能进行访问控制。因为 在大型环境中对 SOA 的需求最为强烈,所以中间件技术的厂商通常把产品的重点放在大型和重型解决方案上。

SOA 和轻量型技术

SOA 背后的思想对于小公司同样是有价值的。重型解决方案的设置成本和所需的人员技能可能使小公司不敢尝试 SOA — 但这是不应该的。暂且不要考虑重型实现,我们先来考察一下 SOA 的基本概念:

  • 从现有的或新的应用程序中提取出服务
  • 把服务集中起来,供许多客户机使用

并没有什么因素妨碍我们用轻量型技术实现这些思想。您可以先建立一个小型 SOA 并逐渐扩展它。如果您的公司以后发展成大型跨国公司,随时可以迁移到重型技术。


什么是 REST?

SOA 通常是用 SOAP 协议实现的,服务由一个 WSDL(Web Services Description Language, Web 服务描述语言)文档来描述。尽管有许多开发工具大大简化了对 SOAP 和 WSDL 的处理过程,但是我仍然把它们看作重型技术,因为如果不使用这些工具,SOAP 和 WSDL 是很难处理的。

也可以通过超文本传输协议(HTTP)发送简单的消息来实现 SOA。这基本上就是 REST 式 Web 服务 (RESTful Web services) 的工作方式。Representational State Transfer(简称 REST,中文翻译“具象状态传输”。REST 这个名称是由 Roy Fielding 首创的)并不是一个协议或技术;它是一种体系结构风格。REST 是 SOAP 的轻量型替代品,它是面向资源的,而不是面向操作的。它常常被归结为远程过程使用 HTTP 调用 GETPOSTPUTDELETE 语句。我认为,这只是第二个重要的步骤。

第一个(也是最重要的)步骤是把所有资源建模为 URL 形式。URL 容易记忆,同时能够访问无数 Web 页面。至少,如果建模方式适当的话,很容易记住 URL(比如 http://www.ibm.com/developerworks/xml/)。如果过分重视 GETPOSTPUTDELETE,就可能产生不容易记忆的 URL,比如 http://www.longfakeurl.com/pol_srdm/70612/9,3993.32?id=78688&lang=cz&st=idx。

在实践中,使用 HTTP 的方法可以进一步限制为 GETPOST 两种方法,因为大多数浏览器对它们的支持很完善。可以对 http://domain.com/myresources/new 执行 POST,以替代对 http://domain.com/myresources 执行 PUT;对 http://domain.com/myresources/oldresource/delete 执行 POST,以替代对 http://domain.com/myresources/oldresource 执行 DELETE

REST 式的设计过程

在设计 REST 式 Web 服务时,可以采用以下四个步骤:

  1. 决定资源及其描述性 URL。
  2. 为每个 URL 上的通信选择一种数据格式。
  3. 指定每个资源上的方法。
  4. 指定返回的数据和状态码。

以下是具体的设计过程。假设您是一家航空公司的开发人员。公司有用于预订航班的软件,还有处理付款(现金和信用卡)的组件。它使用软件跟踪包裹、执行内部资源规划和执行许多其他任务。

假设机场登记处的职员使用一个客户机应用程序,这个程序访问包裹跟踪服务,还使用一个服务为乘客分配座位。处理包裹的地勤人员只需要包裹跟踪服务,不需要其他服务。他们的客户机只允许他们确认已经登记的包裹是否到达了。不允许他们登记新的包裹。

在这个示例中,我们将设计包裹跟踪服务。首先,决定资源:旅行者、航班和包裹(注意,在出现 {id} 的任何地方,都可以填写任意数字):

http://luggagetracking.airlinecompany.com/bags/{id}
http://luggagetracking.airlinecompany.com/flights/{id}
http://luggagetracking.airlinecompany.com/travellers/{id}

为每个资源选择一种数据格式:

包裹:

<bag id="{id}">
<traveller id="{traveller-id}"/>
<flight id="{flight-id}" />
<status>{current-status: departure/plane/arrival}</status>
</bag>

航班:

<flight id="{id}">
<travellers>
<traveller id="{traveller-id-0}" />
<traveller id="{traveller-id-1}" />
<traveller id="{traveller-id-2}" />
</travellers>
<bags>
<bag id="{bag-id-0}" />
<bag id="{bag-id-1}" />
<bag id="{bag-id-2}" />
</bags>
</flight>

乘客:

<traveller id="{id}">
<flight id="{flight-id}" />
<bags>
<bag id="{bag-id-0}" />
<bag id="{bag-id-1}" />
<bag id="{bag-id-2}" />
</bags>
</traveller>

显然,这个模型过于简单了。对于当前的示例,只需要支持两个方法,因此这个模型已经足够了。登记处应该能够为乘客登记新包裹。在把包裹装进飞机时,地勤人员应该能够修改包裹的状态:

  • 对 http://luggagetrackingairlinecompany.com/travellers/{id}/newbag 执行 POST,返回一个 <bag>XML 结构。
  • 对 http://luggagetracking.airlinecompany.com/bags/{id}/status/{newstatus} 执行 POST,返回修改后的 XML 结构。

使用标准的 HTTP 状态作为状态码。成功的操作都会返回 200。如果系统无法根据资源的 ID 找到它,就会返回 404。系统故障导致的任何错误都会返回 500。

代码示例:URL 映射

可以使用多种方式把 URL 映射到实现方法。比较先进的方法可能更灵活,应该用在比较大的应用程序中。这个小示例使用最简单的方法:正则表达式。下面是 BagServlet 上的 post 方法示例,它把 URL 参数传递给底层 servlet。可以在本文的下载文件中找到完整的 servlet 代码。注意,这里没有实现实际的底层服务。 以下是该示例:

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

Pattern pattern = Pattern.compile("^/?.*?/bags/(.*)/status/(.*)___FCKpd___4quot;);
Matcher matcher = pattern.matcher(request.getRequestURI());

if(matcher.matches()) {
String bagId = matcher.group(1);
String newStatus = matcher.group(2);
bagService.changeBagStatus(bagId, newStatus);
}
}

在调用这个 URL 时,如果成功,就会隐式地返回状态码 200。更有意义的是,代码返回 XML 结构。这个示例使用 XStream API 把 Java™ 对象转换成 XML 结构。这个 API 需要的配置非常少,而且主要根据类中的字段名选择元素名。

这个示例代码使用下面这些简单的类:

航班:

package eu.adraandejonge.restfulsoa;

public class Flight {
String id;

public Flight(String id) {
super();
this.id = id;
}
}

乘客:

package eu.adraandejonge.restfulsoa;

public class Traveller {
private String id;

public Traveller(String id) {
super();
this.id = id;
}
}

包裹:

package eu.adraandejonge.restfulsoa;

public class Bag {
private String id;
private Flight flight;
private Traveller traveller;
private String status;

public Bag(String id, Flight flight, Traveller traveller, String status) {
super();
this.id = id;
this.flight = flight;
this.traveller = traveller;
this.status = status;
}
}

假设底层的 BagService 返回一个包裹,包裹的航班 ID 是 1,乘客 ID 是 1,状态是 new。请考虑下面的 GET 实现:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

Pattern pattern = Pattern.compile("^/?.*?/bags/(.*)___FCKpd___8quot;);
Matcher matcher = pattern.matcher(request.getRequestURI());

if (matcher.matches()) {
String bagId = matcher.group(1);

Bag bag = bagService.retrieveBag(bagId);

XStream xstream = new XStream();
xstream.alias("bag", Bag.class);
xstream.alias("traveller", Traveller.class);
xstream.alias("flight", Flight.class);

xstream.useAttributeFor(Bag.class, "id");
xstream.useAttributeFor(Traveller.class, "id");
xstream.useAttributeFor(Flight.class, "id");

String xml = xstream.toXML(bag);
response.getWriter().write(xml);
}
}

在查询这个 URL 时,它会返回以下信息:

<bag id="1">
<flight id="1"/>
<traveller id="1"/>
<status>new</status>
</bag>

还能做什么?

我选择这些示例代码是为了说明,不需要很多底层通信,URL 也能够实现很多功能。对于其他服务,可能需要处理上传给 REST 服务的 XML 结构。XStream 也可以帮助完成这个任务。例如,要想对包裹的 XML 结构进行去序列化,应该调用:

Bag bag = (Bag) xstream.fromXML(xml);

客户机上的应用程序

到目前为止,本文已经讨论了服务器端的实现。客户端上的代码非常相似。客户机可以共享数据类 FlightTravellerBag,并使用 XStream API 对 XML 进行序列化和去序列化。客户机上惟一的新部分是连接 URL 并读取内容或发送内容。通过使用 Java 类库提供的 URL 连接,很容易完成这个任务:

String xml = "<newinput>input</newinput>";

URL url = new URL("http://luggagetracking.airlinecompany.com/bags/1/newmethod");
URLConnection connection = url.openConnection();

// set POST
connection.setDoOutput(true);
Writer output = new OutputStreamWriter(connectiongetOutputStream());
output.write(xml);
output.close();

// display result
BufferedReader input = new BufferedReader(
new InputStreamReader(connection.getInputStream()));

String decodedString;
while ((decodedString = input.readLine()) != null) {
System.out.println(decodedString);
}
input.close();

与 Ruby on Rails 等技术的互操作性

尽 管 REST 并没有明确的规范来规定如何实现它,但是对 REST 的开箱即用支持越来越多了。因此,虽然没有需要遵循的标准,但是您需要遵守一些约定。例如,Ruby on Rails 提供 ActiveResource。如果遵守 Rails 对 URL 和输出格式的约定,就很容易用最小的开销把 Rails Web 客户机连接到 Java REST 式 Web 服务。

可伸缩性和向重型 SOA 的迁移

分享这篇文章……

digg 提交到 Digg
del.icio.us 发布到 del.icio.us
Slashdot Slashdot 一下!

随 着应用程序环境的增长,很可能会对越来越多的 REST 实现细节进行抽象。当增长和抽象发展到一定程度之后,从轻量型技术迁移到重型的 SOA 技术可能会节省成本。这需要把服务背后的实际业务逻辑提取出来,并重新包装在新环境中的一个 SOAP 包中,这个过程应该不是太难。

寻找应用 REST 式 SOA 的机会

航空公司只是本文使用的一个示例。实际的航空公司规模都比较大,它们应该直接使用重型技术。如果您为小公司工作,可能需要发挥想像力,寻找到在实践中应用 SOA 和 REST 原则的最佳方式。花些时间考虑这个问题,这会带来长远的回报!

分享到:
评论

相关推荐

    lectures:大学课程和其他演讲,主要涵盖Web体系结构,REST,SOA,XML(XSLTXSD)和类似内容

    大学课程和其他演讲,主要涵盖Web架构,REST,SOA,XML,IoT,语义Web和相关主题。 在线的 实际演示的在线版本,可以发现 (或在所有大学课程的列表 ),但旧的演示文稿,你看GitHub存储库中没有一部分(如果我有...

    Asp.Net及相关技术介绍

    XML-RPC,SOAP,REST, SOA Asp.Net WebForm,WebService, WCF Asp.Net WebAPI, Asp.Net MVC,JSON Asp.Net Routing, MVVM,DOM HttpModule, HttpHandler, Ajax Jquery JS,Knockout JS 内容提纲如下...

    XML与Web服务和SOA有何关联?

    尽管可以使用许多技术来实现面向服务体系结构(SOA),不过最常用的还是使用 Web 服务,这意味着要使用 XML。SOAP 和 REST 是实现 Web 服务最流行的两种方法,这两者都基于 XML。一个例子比如说,通过将这个 SOAP ...

    基于Web的连接框架CDIF.zip

    CDIF是世界上第一种基于REST和JSON的SOA软件框架,提供了与基于XML的WSDL语言和SOAP协议同等抽象能力、但简洁得多的基于JSON的实现,也非常适合用于描述微服务架构的API接口。CDIF提供了完整的服务注册和发现能力,...

    a-simple-mvc-rest-service:包含带有 TDD 的示例模块的简单 RESTJersey 项目,用 Java 实现

    该项目是使用市场标准开发的,例如: MavenEJB 朱尼特RESTful(泽西岛) 莫基托该项目是使用标准/技术开发的,例如: MVC SOA 休息TDD 如果有任何疑问或问题: 1 - 如果您尚未为 glassfish 配置运行时,请使用此 ...

    soaba:楼宇自动化 SOA

    Web Prototype App 将使用此 REST 接口来控制和公开网关驱动程序功能。 组件和目标 网关驱动程序,用于与 KNX 设备交互。 网关驱动程序的主要目的是抽象处理特定类型网关的复杂性,从而抽象它们的下层通信特殊性...

    Soapui Pro v5.1.2破解文件

    soapUI是一个开源的、跨平台的测试工具。是SOA(面向服务的建筑)和基于REST的Web服务。这是一个技术术语中,全自动功能和回归测试平台可以提高你的应用程序和服务的可利用性进行测试

    Apache Axis2 Web Services, 2nd Edition.pdf

    Chapter 3, Axis2 XML Model (AXIOM) - Learn about the heart of a web service framework and learning more about XML processing in Axis2. Chapter 4, Execution Chain - Learn how to extend the core ...

    狂战士

    在开发使用Django和动手编码语言(Java和Python)的实现Model View Control架构的Web应用程序方面的丰富经验。 熟练开发持续集成/交付管道。 对新开发的功能执行单元测试和系统集成测试 根据应用程序支持和行业...

    enterprise_rails.pdf

    REST Versus XML-RPC Versus SOAP 212 XML-RPC 212 SOAP 214 15. An XML-RPC Service ................................................... 217 ActionWebService and Rails 2.0 217 Creating an Abstraction ...

    SoapUI-x64-5.2.1

    soapUI是一个开源的、跨平台的测试工具。是SOA(面向服务的建筑)和基于REST的Web服务。

    RESTful Web Services.rar

    Processing the Response: XML Parsers 38 JSON Parsers: Handling Serialized Data 44 Clients Made Easy with WADL 47 3. What Makes RESTful Services Different?.... . 49 Introducing the Simple Storage ...

    licas:基于智能服务的网络的框架。 移动兼容。-开源

    通信包括XML-RPC,REST和Web服务。 其他功能包括服务保护,管理脚本,元数据,查询过程,自主,基于代理或自组织。 该系统的特殊之处在于其AI和文本处理功能。 特别是,有一个带有BPEL样式执行脚本的Autonomic ...

    HTTP, Quality Assurance Toolkit-开源

    基于jython / grinder(http://grinder.sf.net)的HTTP功能和非功能(负载和性能)工具包...包括支持以下功能:SOA服务,REST,json / xml编码,AES和WS安全性...和一个用来收集请求的存根

    Crispy-开源

    它是一种轻量级的API,用于调用Web服务(RMI,CORBA,WebService(SOAP),XML-RPC,EJB,Hessian,Burlap,REST等),以及如何调用简单的Java Object。 您可以将Crispy集成到面向服务的体系结构(SOA)或富客户端...

    RESTful Web Services 中文版.rar

    第3章:REST式服务有什么特别不同?.........49 介绍Simple.Storage.Service...............49 S3的面向对象设计.........................50 资源.....................................52 HTTP响应代码...........

Global site tag (gtag.js) - Google Analytics