什么是 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 原则的最佳方式。花些时间考虑这个问题,这会带来长远的回报!

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

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

    JDK1.5需要添加jar包,1.6以后就不需要了<dependency> <groupId>stax</groupId> <artifactId>st ...

  2. 【Java】Java XML 技术专题

    XML 基础教程 XML 和 Java 技术 Java XML文档模型 JAXP(Java API for XML Parsing) StAX(Streaming API for XML) XJ(XM ...

  3. SOA (面向服务的架构)

    面向服务的体系结构,是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台.操作系统和编程语 ...

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

    MD5加密 将字符串进行加密,无法解密.网上的解密方式也都是在库里找,找不到也没有. 1 protected void Page_Load(object sender, EventArgs e) 2 ...

  5. Linq世界走一走(LINQ TO XML)

    前言:Linq to xml是一种使用XML的新方法.从本质上来说,它采用了多种当前使用的XML处理技术,如DOM和XPath,并直接在.NET Framework内将它们组合为一个单一的编程接口.L ...

  6. 进程、线程、GDI+、XML、委托

    进制 表示某一位置上的数运算时是逢X进一位.二进制就是逢二进一, 十进制是逢十进一,十六进制是逢十六进一,以此类推. so:二进制001010101只有0和1计算机中的数据都是二进制表示,四进制以0. ...

  7. 浅析深究什么是SOA?(转)

    http://blog.vsharing.com/fengjicheng/A1059842.html 阅读提示: 本文探讨SOA概念背后的核心内涵,如何将SOA落地的实务方法. 金蝶中间件作为全球领先 ...

  8. 浅析深究什么是SOA?

    浅析深究什么是SOA? http://blog.vsharing.com/fengjicheng/A1059842.html 金蝶中间件有限公司总经理 奉继承 博士 阅读提示: 本文探讨SOA概念背后 ...

  9. 笔记:Jersey REST 传输格式-XML

    XML类型是使用最广泛的数据类型,Jersey 对XML类型的数据处理,支持Java领域的两大标准,即JAXP(Java API for XML Processing,JSR-206)和JAXB(Ja ...

随机推荐

  1. Linux下面如何安装Django

    首先你需要肯定你的机子上装了Python 现在ubuntu已经自带,所以不必操心 当然你可以在你的机子下测试一下,只需在 terminal 下输入 python 如果出现下面的界面就说明你机子已经装了 ...

  2. android-exploitme(五):不安全的数据存储

    今天我来看看如果android将数据存储在sdcard,它的权限是什么样的 1. 打开emm软件,做一笔转账.

  3. DB2操作流程

    DB2如何创建表空间 如何创建数据库 如何创建缓冲池标签: db2数据库system脚本linuxwindows2012-06-13 19:16 8411人阅读 评论(0) 收藏 举报 版权声明:本文 ...

  4. JVM垃圾回收机制总结(5) :JDK垃圾收集器的配置命令

    以下配置主要针对分代垃圾回收算法而言. 堆大小设置 年轻代的设置很关键 JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理 ...

  5. MyBatis学习总结_18_MyBatis与Hibernate区别

    也用了这么久的Hibernate和MyBatis了,一直打算做一个总结,就他们之间的优缺点说说我自己的理解: 首先,Hibernate是一个ORM的持久层框架,它使用对象和我们的数据库建立关系,在Hi ...

  6. Java:日历类、日期类、数学类、运行时类、随机类、系统类

    一:Calendar类 java.util 抽象类Calendar   1.static Calendar getInstance()使用默认时区和语言环境获得一个日历. 2. int get(int ...

  7. 关于Netty4.x中文教程系列更新进度的说明和道歉

    最近一些事情.貌似发现很久没更新教程了.这里和大家说一声对不起.教程5的前半部分差不多年前就写好了.但是由于年前我在的项目组项目进度比较紧张.一直在加班.教程的后半部分就一直没有写.年后由于一些公司人 ...

  8. 关于utf8 unicode gbk 编码乱码汇总

    首先从一个问题说起: 插入一个中文到blob类型(mysql编码是utf-unicode-ci). insert into  blobtype(data) values('中文你好') 复制数据显示为 ...

  9. c# 网络是否连接

    c#  网络是否连接 方案一: using System; using System.Collections.Generic; using System.Linq; using System.Text ...

  10. 360每日自动签到,领取积分 (java httpclient4.x)

    如何登陆360,并每日自动签到这次的难点主要集中在登陆这里了,开始抓包发现360登陆验证很麻烦,但是后来发现一个简单的方法.因为我安装了360安全卫士,发现点击那个金币的按钮能直接验证登陆,哈哈~所以 ...