使用 XML 实现 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 调用 GETPOSTPUT 和 DELETE 语句。我认为,这只是第二个重要的步骤。

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

在实践中,使用 HTTP 的方法可以进一步限制为 GET 和 POST 两种方法,因为大多数浏览器对它们的支持很完善。可以对 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/(.*)$"); 	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/(.*)$"); 	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); 

客户机上的应用程序

到目前为止,本文已经讨论了服务器端的实现。客户端上的代码非常相似。客户机可以共享数据类 FlightTraveller 和 Bag,并使用 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 的迁移

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

寻找应用 REST 式 SOA 的机会

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

时间: 2024-10-19 22:56:53

使用 XML 实现 REST 式的 SOA的相关文章

java JAXB + STAX(是一种针对XML的流式拉分析API)读取xml

<dependency> <groupId>stax</groupId> <artifactId>stax-api</artifactId> <version>1.0.1</version> </dependency> 使用XMLStreamReader和XMLEventReader读取XML文件 1 <?xml version="1.0" encoding="UTF-8&q

浅析深究什么是SOA?

阅读提示: 本文探讨SOA概念背后的核心内涵,如何将SOA落地的实务方法. 金蝶中间件作为全球领先的SOA解决方案供应商,拥有中国唯一全球第四通过Java EE 5.0认证的SOA基础平台:中国唯一完整实现TOG-SOA标准模型的中间件解决方案:与北京大学合作,国家“核高基”科技重大专项成果,承担振兴国家基础软件的责任和使命: 中国唯一入选Gartner全球有能力提供SOA服务的十九家软件厂商.本文就是根据金蝶中间件readySOA解决方案整理而成的通俗科普文章. 本文介绍的主要内容包括:为什么

【Java】Java XML 技术专题

XML 基础教程 XML 和 Java 技术 Java XML文档模型 JAXP(Java API for XML Parsing) StAX(Streaming API for XML) XJ(XML Enhancements for Java) XML 验证 XPath XQuery XSL 转换处理器 XStream 数据绑定 本专题汇总了大量面向 Java 开发人员的 XML 技术文章和教程,内容涉及 XML 基础.Java XML 的文档模型.编程 API 与数据绑定框架以及 Java

SOA概念

浅析深究什么是SOA?[转] 金蝶中间件有限公司总经理 奉继承 博士 阅读提示: 本文探讨SOA概念背后的核心内涵,如何将SOA落地的实务方法. 金蝶中间件作为全球领先的SOA解决方案供应商,拥有中国唯一全球第四通过Java EE 5.0认证的SOA基础平台:中国唯一完整实现TOG-SOA标准模型的中间件解决方案:与北京大学合作,国家“核高基”科技重大专项成果,承担振兴国家基础软件的责任和使命: 中国唯一入选Gartner全球有能力提供SOA服务的十九家软件厂商.本文就是根据金蝶中间件ready

4、C#进阶:MD5加密、进程、线程、GDI+、XML、委托

MD5加密 将字符串进行加密,无法解密.网上的解密方式也都是在库里找,找不到也没有. 1 protected void Page_Load(object sender, EventArgs e) 2 { 3 string s = "123"; 4 Response.Write(getMd5(s)); 5 } 6 public string getMd5(string str) 7 { 8 MD5 md5 = MD5.Create();//MD5抽象类无法实例化 实例化该方法 9 byt

1 SOA概念的导入

1 SOA概念的导入 1.1  SOA概念 随着我国各行业信息化建设的不断深入,企事业单位和政府部门逐步建立起的大批计算机信息系统和各类数据信息因缺乏有效衔接,导致信息资源共享难."信息孤岛"现象普遍存在.与此同时,对于企事业单位,随着经济全球化大环境下的市场竞争日益激烈,企业正在通过加快管理转型.技术创新.新产品研发以及业务策略调整等方式来提升自己的核心竞争力.持续占有并扩大市场份额.对于各级政府部门,在以"大部制"为核心的政府行政管理体制改革的驱动下,以&quo

[转载] 使用StAX解析xml

StAX 概述 从一开始,Java API for XML Processing (JAXP) 就提供了两种方法来处理 XML:文档对象模型(DOM)方法是用标准的对象模型表示 XML 文档:Simple API for XML (SAX) 方法使用应用程序提供的事件处理程序来处理 XML.JSR-173 提出了一种面向流的新方法:Streaming API for XML (StAX).其最终版本于 2004 年 3 月发布,并成为了 JAXP 1.4(将包含在即将发布的 Java 6 中)的

[Android]继承式UI界面布局设计

一般而言,Android界面布局使用聚合的方式比较多,这种方式要求首先构建一批能够复用的组件,然后在Activity的布局文件中进行聚合.尽管这种方式能够完成组件的复用,但如果这些组件在不同Activity中的布局有很多相同点的时候,也还是会带来很大程度的冗余(代码).本文介绍一种比聚合更加有效的界面布局方式--继承式布局. 对于类的继承和对象的聚合之间有哪些相同点和不同点,分别适用于哪种场景,相信大家已经深有体会.在此就不多讲了.其实类比过来,Android的界面布局也是如此.假设我们需要实现

SOA 一些基本概念

SOA---面向服务的体系结构(service-oriented architecture,SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来;接口是采用中立的方式(没有强制绑定到特定的实现上,称为服务之间的松耦合)进行定义的,它应该独立于实现服务的硬件平台.操作系统和编程语言. 基于 SOA 的系统可以使用面向对象的设计来构建单个服务,但是其整体设计却是面向服务的.由于它考虑到了系统内的对象,所以虽然 SOA 是基于对象的,但是作为一个整