基于Tuscany的SDO实践
http://dev2dev.bea.com.cn/techdoc/2007/06/java-soa-Tuscany-SDO.html
随着SOA理念的流行和 Web Service等技术的广泛应用,我们发现在越来越多的系统中,我们需要访问各种不同的底层数据,这些数据包括关系型数据库,EJB组件,XML文件或数据库,Web 服务, JSP 页面数据等等。为了能够访问和操作这些数据,开发人员必须了解针对不同数据源操作的规范和API。SDO(Service Data Object)为我们提供了统一的数据应用开发框架,它提供了对多种企业信息系统 (EIS) 的统一的数据访问,包括数据库、遗留应用程序(使用 JCA)、XML 或者是 Web 服务数据源。通过使用 SDO 的一种独特而简单的模型,应用程序摆脱了使用多种 API 和框架进行数据访问的复杂工作。从而使开发人员只需了解一种API便可操作上述数据。下面我们就来了解一下什么是SDO。
SDO(Service Data Objects)服务数据对象,是BEA 和 IBM 共同发布的一项规范。SDO是Java平台的一种数据编程架构和API,它统一了不同数据源类型的数据编程,提供了对通用应用程序模式的健壮支持,并使应用程序、工具和框架更容易查询、读取、更新和检查数据。
这里需要说明,SDO不是一种针对数据访问和持久化的技术,而是一种数据编程架构和一组API。SDO主要用于简化数据编程,让开发人员能集中解决业务逻辑问题而不是底层技术. SDO通过以下手段简化数据编程:
统一不同类型的数据源的数据访问编程
提供一套一致的应用模式的支持
让应用、工具和框架能够更便捷地查询、浏览、绑定、更新和获取数据的元信息。
SDO的一个关键目标是鼓励大家采用公用的 J2EE 模式,这也是 SDO 体系结构以一些广为人知的模式为基础的原因,例如传输对象 (Transfer Object)、数据访问对象 (Data Access Object)、传输对象组装程序和 Domain Store等。如果使用了 SDO,应用程序就可以从这些经过了验证的设计策略中受益,从而可以推动分层技术和松耦合的发展。为了更好的理解SDO框架,我们有必要对其中使用到的J2EE模式有所了解。
为了从不同的数据源获取和存储数据,我们时常将这样的逻辑封装到业务对象中,这样导致数据与特定的数据源和持久化策略紧密耦合。当我们需要变更数据源或存储方式时,就需要修改所有的业务对象。
Domain Store 将持久策略与实现从业务对象中分离出来,使数据的表示独立于其数据源。它利用StoreManager, TransactionManager, StateManager这样的管理类对数据对象进行存储操作,这种级别的数据提取有很多优点,例如当数据源发生改变时,只需增加或修改相应的持久实现即可,从而使数据操作变得更容易,实现了不同层之间的松耦合。SDO正是采用了Domain Store这种 J2EE 模式,将数据与对数据源的存取机制很好的解藕了。
SDO使用了传输对象 (Transfer Object) 和传输对象组装程序 (Transfer Object Assembler) 模式,当数据封装到 SDO 对象中后,它就可以在 J2EE 层间高效地传输。这里需要注意的是,SDO 的动态 API 模式与传统的值对象(Value Object) 模式有所不同,它更像是动态赋值弱类型值对象(Dynamic Create Value Object 模式)。对于熟悉 JDBC 概念和 java.sql.ResultSet 接口的读者来说,SDO 的动态 API 模式是很容易理解的。就像 JDBC 一样,您可以通过名称或索引来访问它的属性值。如果在开发阶段数据结构就可以确定的话,SDO 体系结构还提供了静态 API 功能。例如,如果数据源是一个带有明确定义模式(xsd 文件)的 XML 文件的话,则 SDO 将支持 Java 代码生成和 Java 绑定。虽然这已经超出了 SDO 规范的范围,但是绑定技术可能会集成一些对 SDO 的支持,例如 XML Data Binding的 Java 体系结构 (JAXB)。
SDO由多种不同组件组成,理解他们的概念和作用是理解SDO框架的基础。
数据源不限于后端数据源(如持久存储数据库)。数据源以自己的格式保存数据。只有 DMS 访问数据源,SDO 应用程序不访问数据源。SDO 应用程序可能只使用数据图中的数据对象。
DMS 是一种组件,它负责提供某些方法来组装数据图,也负责将数据更改保存回数据源。典型情况下,将会有多种不同的 DMS 类型,每种类型对应着一种特定的数据源和技术(XML、JMS、JCA、JDBC 等等)。DMS 总是以同一种格式(数据图)返回信息,它隐藏了实际的数据存储信息,在 SDO 应用程序和 EIS 之间提供了一层数据提取的功能。数据中介框架不属于 SDO 1.0 规范,换句话说,SDO 1.0 没有涉及具体的 DMS。常见的 DMS 有 JDBC DMS、实体 EJB DMS 和 XML DMS 等。
数据对象是 SDO 的基本组件。简单地说,它是由属性的键/值对组成的,每个值都可以是原始的数据类型,或者是另一个数据对象。数据对象提供了易于使用的创建和删除方法(带有不同签名的 createDataObject() 和 delete() ),获得自身类型(实例类、名称、属性和名称空间)的反射方法。数据对象都链接在一起,包含在数据图中。数据对象是可序列化的。
数据图是一个描述数据的分层结构,它包括一个数据对象树和另一个称作变更摘要 (Change Summary) 的结构(如图所示)。变更摘要记录了数据图中所有数据对象的历史更改信息。此外,由于数据图是由数据对象组成的,因此它是可序列化的。
数据图由 DMS 生成,供 SDO 客户使用。修改后,数据图被回传给 DMS 更新数据源。SDO 客户机可以遍历数据图,读取和修改数据图中的数据对象。当在应用程序组件(比如服务调用期间的 Web 服务请求者和提供者)之间进行传输、组件到 DMS 的传输(或者保存到磁盘)的时候,数据图被序列化为 XML。SDO 规范提供了序列化的 XML Schema。
变更摘要包含在数据图中,表示对 DMS 返回的数据图的修改。变更摘要最初是空的,随着数据图的变化逐渐填充。在后台更新时,DMS 使用变更摘要将修改应用于数据源。变更摘要提供了数据图中被修改的属性(包括原来的值)、新增和删除的数据对象的列表,从而使 DMS 以递增方式高效地更新数据源。只有当变更摘要日志功能被激活时,才会将信息添加到数据图的变更摘要中。变更摘要提供了让 DMS 打开和关闭日志功能的方法。(后面的例子中将会看到)
数据对象用一系列属性保存其内容。每个属性都有一个类型,该类型既可以是基本类型(如 int )这样的属性类型,也可以是通用数据类型(如 Date ),如果引用的话,还可以是其他数据对象类型。每个数据对象都为属性提供了访问和设置方法(getter 和 setter)。这些访问器方法有不同的重载版本,可以通过传递属性名( String )、编号( int )或者属性元对象本身来访问属性。String 访问器还允许使用类 XPath 的语法访问属性。比如,可以对保单数据对象调用 get("policy[policyNo=20070522]") 来访问编号为20070522的保单。序列更加高级,可以保持不同种类的属性-值对列表的顺序。
在有了以上这些SDO基本知识之后,我们迫切的希望尝试SDO。这里要为大家介绍一种SDO框架Tuscany并结合它演示一个简单的SDO例子。
2005年12月,Apache在BEA 和IBM 的推动下,启动了Tuscany项目。Tuscany的实现遵循了SCA 和SDO规范,以及包括一个支持SDO的Data Access Service (DAS)。
可以从Tuscany的网站下载最新的tuscany 版本,也可以通过SVN获取最新的tuscany代码,并通过maven产生你需要的Eclipse或IDEA项目。
http://incubator.apache.org/tuscany/sdo_downloads.html
创建一个新的java项目,命名为tuscanyTest,由于目前公司使用的开发工具是IDEA, 因此这里以IDEA的配置为例,Eclipse中的配置大致相同。在项目中添加以下jar包。
创建一个新的测试类并命名为SDOTest,接着我们就可以开始体验SDO了。
我们先定义数据对象的类型,用XSD文件表示:
然后我们构造一组实验数据,以XML数据文件的形式存储。
首先我们利用XSDHelper导入之前定义的类型(XSD)文件来声明数据对象的类型。然后通过XMLHelper从XML数据文件中载入数据,并通过getRootObject() 方法返回数据对象(Data Object)。
XSDHelper.INSTANCE.define(ClassLoader.getSystemResourceAsStream(PO_XSD_RESOURCE), null); purchaseOrder = XMLHelper.INSTANCE.load
(ClassLoader.getSystemResourceAsStream(PO_XML_RESOURCE)).getRootObject();
接着创建数据图(Data Graph),并将purchaseOrder数据对象设置到数据图对象中。SDOUtil 是Tuscany中最重要的SDO工具类之一。它负责创建数据对象,数据图等重要的操作。
DataGraph dataGraph = SDOUtil.createDataGraph(); SDOUtil.setRootObject(dataGraph,purchaseOrder);
从数据图中获取变更摘要,并开始对数据图的变更进行记录,这里我们改变了数据对象purchaseOrder中orderDate属性的值。
ChangeSummary changeSummary = dataGraph.getChangeSummary(); changeSummary.beginLogging(); purchaseOrder.setString(purchaseOrder.getProperty("orderDate"),"2007-03-18"); changeSummary.endLogging();
变更摘要的isModifed方法返回数据图是否更改的布尔值, getOldValue方法可以获取数据图更改前的值, undoChanges方法可以回滚数据图的变更。我们一次试验这几个常用方法。
boolean isModified = changeSummary.isModified(purchaseOrder); System.out.print("\nIs data changed in DataObject: "+isModified); ChangeSummary.Setting oldOrderDate = changeSummary.getOldValue(purchaseOrder,purchaseOrder.getProperty("orderDate")); System.out.print("\nThe old ordere date is: "+oldOrderDate.getValue()); printPurchaseOrderSummary(purchaseOrder); changeSummary.undoChanges(); printPurchaseOrderSummary(purchaseOrder);
printPurchaseOrderSummary方法在控制台中打印数据对象,我们清楚地发现会滚之前和之后数据对象的变化。
这个例子非常简单,但读者可以从中了解到SDO的一些重要组件和用法。读者也可以在此基础上增加新的测试来深入学习SDO。
我们通过一个非常简单的Tuscany SDO例子,展示了SDO的一些功能和特点,并帮助读者了解SDO的设计思想和概念。
SDO 规范 1.0 版于 2003 年末提交给 Java Community Process,并获得了批准,它仍在不断的发展中。SDO能够帮助我们解决通用企业应用程序的一个重要问题: 异构数据访问。SDO 为业务数据提供了一种中立的表示方法,建立了一种与数据源无关的模型,降低了耦合度。随着SOA的广泛应用,相信SDO会成为 SOA 应用程序的一个重要组件。
Apache Tuscany 主页
http://cwiki.apache.org/TUSCANY/
Tuscany SDO 下载页面
http://cwiki.apache.org/TUSCANY/sdo-java-releases.html
Introduction to Service Data Objects
http://www-128.ibm.com/developerworks/java/library/j-sdo/
Service Data Objects For Java Specification
http://www.osoa.org/display/Main/Service+Data+Objects+Specifications
<!--文章其他信息-->
作者简介 | |
陈逸鹤 是eBaoTech R&D事业部软件工程师,擅长使用BEA WorkShop开发基于 WebLogic Server的J2EE应用,熟悉流行的开源项目Spring,Beehive,XML Beans等。 |