如今,组织内及跨组织的集成领域面临着一个共同的挑战,这就是发布
Web 服务以向外部使用者提供信息,这通常伴随着提交和操纵信息的操作。这些信息通常存储在 Oracle
Database 中。一直以来,此数据库可通过 Forms 应用程序、批处理程序以及某些 .NET 或
Java web 应用程序来访问。然而,对于 DBA、开发人员、架构师和任何其他相关人员来说,提供 Web
服务却是一件新事物。
本文介绍一家现实中的组织在面临提供数据服务的挑战时所采取的步骤和考虑事项。这家组织的初始状况(也是我们在本文中的初始状况)是这样的:拥有一个数据库并且其中包含数据、当时的技能储备以及对许多
Web 服务的需求。当时,这家组织确定他们需要实现企业服务总线设计模式,探索了该模式的可能实现方式,并选择了一种对新的开发技能和软件许可要求最少的简单实现方式。下面我们将遵循他们的思路、可选方式和最终选择来进行。
我们用一个简单的示例 Jukebox 来演示该组织选择用来通过 Web
服务提供数据库数据的方法。您可以下载此示例的源代码自行尝试。注意:所需的基础架构包括 Oracle Database(10g
XE 就可以)和与 Oracle WebLogic Server 集成的 Oracle JDeveloper
11g。
挑战
在本文中,我们正在讨论的这家组织称为“Stuff, Inc.”。该组织所面临的挑战很简单:外部各方请求通过
Web 服务访问信息。这些信息保存在 Stuff, Inc. 的企业 (Oracle) 数据库中。
![](images/2013112521.png)
该组织以前没有 Web 服务方面的经验。他们可以运行几个访问数据库的简单
Web 应用程序。这些应用程序是使用各种开源 Java 框架开发的,部署在开源 GlassFish 应用服务器上。对
Stuff 的管理层而言,开源是他们的首选(尽管并非是他们的信条),他们对 Oracle Forms 和
Reports 的长期持续投入表明了这一点。Stuff 的开发部门非常精通 SQL、PL/SQL 和 Forms,并且拥有一些
Java 程序员。
项目经理、企业架构师和高级开发人员坐下来讨论使用 Web 服务前端在更大的范围提供数据库的办法。开始,讨论集中于架构而非实现。他们采纳了企业服务总线架构模式并将其应用于
Stuff, Inc. 的情况。
![](images/2013112522.png)
Wikipedia 中对此 ESB 模式的定义是“一种软件架构模型,用于为相互交互的软件应用程序设计和实现彼此之间的交互和通信”。换句话说:分离交互双方:数据服务的调用者无需了解也不依赖于数据库的位置和服务的技术实现。此模型有许多种不同的描述方式,并且已通过大量软件产品进行了实现。它帮助了
Stuff 的员工组织讨论、认识设计和实现所需的关键要素,还引导他们考虑正式的 ESB 产品。
尽管有文献建议让企业服务总线承担大量功能,但 Stuff, Inc. 确定 ESB 要承担的关键角色通常标识为
VETRO:
验证消息 (V) — 一旦定义服务合同,使用者和后端均不必担心需要处理不符合合同的消息;ESB
必须负责免除双方处理非兼容消息的负担。
通过联络多个源充实内容 (E) — 通过企业服务总线提供的服务可以利用多个后端资源(与其中一个交互)来满足服务的义务
消息之间按照服务合同和企业数据库和其他后端系统的数据结构和数据模型的指定进行转换
(T);ESB 提出消息定义,定义不包含技术细节,没有旧数据模型的缺点并且在与充满这些问题的后端交互时不存在跨系统不一致性
路由 (R) 消息和联络后端资源(即操作)— 根据服务所接收请求内容的不同,应将消息路由到需要调用的特定后端系统。
ESB 层可承担的其他 (O) 功能包括安全、缓存、监视和 SLA 管理、限流和排队/暂存、拆分和合并(针对并行处理)、在同步与异步之间进行适配转换,以及桥接各种协议和技术。
无论实际将采用何种方式实现服务层,Stuff 的团队都确定他们要实现 VETRO
模式。任何技术设计和对工具和技术和任何选择都将必须为这些核心功能提供支持。此外,对 Stuff 非常重要的一点是提出一种具有灵活性的设计,因为已经明确这些最初的少数数据服务在不远的将来将经历相当大的变化并将补充其他服务。另外,某些新的外部方也可能加入,他们有自己特定的对初始服务集的需求(在外部类似但不一样)。
该组织与外部合作伙伴就 Web 服务合同达成一致。这意味着确定了服务和操作的名称,以及要交换的
XML 消息的定义。从技术角度来说,这意味着建立了抽象 WSDL(以 Web 服务定义语言表示的服务合同)和
XSD(由 XML 模式定义描述的 XML 结构)。WSDL 加上 XSD 确定了 Stuff 的实现团队需要努力实现的目标。
![](images/2013112523.png)
有此计划外观的定义(通过 HTTP 通信协议带 XML 有效载荷的 SOAP
消息)和现有后端(Oracle Database 及其 PL/SQL 和 SQL API 以及数据类型组成的环境),Stuff
知道 ESB 模式的实现还必须桥接这两个环境。注意,Stuff 先前已经决定将采用 Java 平台和 Java
EE 应用服务器作为其中间件。将在此平台上提供 Web 服务以方便外部使用者。
连接数据库
很明显,从 Java EE 应用服务器到 Oracle Database 的桥接是 Stuff 的服务架构设计的一个重要方面。在做任何最终决策之前,非常重要的是,要分析可以用来连接数据库的所有不同方式及其对应用服务器端以及数据库端的影响。
下图显示了从 JEE 应用服务器连接 Oracle Database 的各种方式。它区分了通过
HTTP 的通信、通过 TCP 经由 JDBC(到数据库监听程序)的通信以及通过其他通道(包括电子邮件和文件系统作为中介)的通信。该图中,蓝色连接表示非类型化文本形式(包括
XML、JSON 和逗号分隔值格式)的通信,红色连接表示强类型交互。
![](images/2013112524.png)
此处显示的一些交互依赖于 Oracle WebLogic Server
中可用的技术适配器(例如,当安装了 Oracle SOA Suite 或 Oracle Service
Bus 时)。Stuff, Inc. 并未计划使用 Oracle SOA Suite 或 Oracle
Service Bus,因此没有相应适配器供其使用。不过,Stuff 的团队知道,当服务、服务调用和服务使用者的数量增加,或者服务的复杂性增大时,他们很可能会重新考虑使用这些产品。理想的设计将允许在后续阶段轻松插入
ESB 产品。
Stuff, Inc. 的开发团队主要精通 Oracle 数据库应用程序开发。这些开发人员擅长 SQL
和 PL/SQL,对数据模型了如指掌,对性能、数据完整性和安全性高度负责。这些技能、知识以及责任心为实现
Web 服务提供了基础,架构设计团队希望充分利用这些。Stuff 关于企业数据库的一条原则就是不在数据库之外定义
SQL:所有访问均通过封装 SQL 的 PL/SQL API 完成。这样数据库开发人员确保不会有未经测试、拙劣的查询威胁性能或防碍未来的数据模型优化。在执行数据操作时,PL/SQL
API 将能够验证、充实传入的数据并将其路由到其所属目标表。
Stuff 已在其数据库开发中采用了抽象数据类型,即用户定义的类型。它已认识到,使用这些类型有助于干净、优美地开发数据
API、构造和传递使用多个查询从多个表组装的复杂嵌套数据结构。这些类型还有助于实现 API 的操作和参数与底层表结构分离,在这一点上远优于(举例来说)使用
ref cursor。注意,尽管 PL/SQL 开发人员花了一段时间才接受基于类型的方法,但现在他们已在狂热地使用它。
Stuff 的另一项准则是数据库不应疲于迎合每个应用程序或 Web 服务的确切数据结构要求。由 PL/SQL
API 向所有使用者提供通用数据服务,而非根据各使用者的特殊需要进行细微调整。对于所关注的 Web 服务挑战,这意味着数据库将提供服务所需的数据,但可能与服务合同所要求的结构不完全一样。这样没有问题,因为转换已被确定为
ESB 实现的一项重要任务。
重点在于应最大程度减少服务器到数据库的往返次数。这意味着,如果应用程序或服务所需的数据集不能通过 PL/SQL
API 中的单个函数获取,则在 Stuff 的惯例是使用一个新的操作扩展该 API,该操作很可能是一个非常薄的包装器,包装组合在一起的两个或更多个现有操作。组合和分解是用
PL/SQL 完成的,这样使用者通过一个数据库调用即可完成业务。
架构设计团队坐在一起考虑了所有以上情况,然后重新站起来聚在白板前讨论 ESB
模式的实现。
![](images/2013112525.png)
上图显示他们深思熟虑的结果,数据库在最右侧,Web 服务在左侧。分离、封装、专业化和灵活性成为讨论的焦点,该场景中,一边是服务合同,另一边是数据库和数据模型,并决定采用
JEE 应用服务器而非 ESB 产品。
团队最后得出结论:基于类型的 PL/SQL API 尚不便使用 Java
代码通过 JDBC 进行访问。不过,此 API 的本质不应有损,尤其是因为以后(在引入 Oracle SOA
Suite 或 Oracle Service Bus 之后)可能使用的数据库适配器非常适合与基于类型的过程进行交互。相反,团队决定将基于类型的
API 包装到一个薄层中,该层负责在 XMLType 与该 API 的用户定义类型之间进行转换。此转换是通用的,不需要类型特定的代码。
![](images/2013112526.png)
设计端到端 Web 服务架构
Stuff 的架构团队为数据 Web 服务提出了以下设计:
![](images/2013112527.png)
Web 服务合同(WSDL 和 XSD)用于生成 JAX-WS Web
服务:该服务是一些共同实现合同的 Java 类的集合。这是服务的前端。它部署在 JEE 应用服务器上,从服务器接收服务请求(带有
XML 数据有效载荷的 SOAP 消息)。通过 JAXB 绑定基础架构,它将 XML 有效载荷转变成从
XML 消息结构的 XSD 定义衍生生成的类的实例。在执行这个 XML 到 OO 转换时,可根据 XSD
对传入消息进行验证。
安全策略可以在 Java 类中使用 JAX-WS 批注进行配置,也可以在部署期间或部署之后在应用服务器中配置。这些策略管理身份验证、授权、数字签名和消息加密等要求。
该团队决定通过 XML 与数据库进行通信,使用数据库的 XMLType,并让 XMLType 与数据库的
PL/SQL API 中使用的用户定义类型相互转换生成。该团队得出结论:使用 XSLT 可以最轻松地将外部
Web 服务合同中定义的 XML 结构映射到 PL/SQL API 所需的内部 XML,尤其是在可能必须将同一内部
XML 映射到各种不同外部 XML 格式以供不同服务使用者使用的情况下。团队在 Java 中采用了多阶段方法,分为四个简单步骤:
1、基于 WSDL 和 XSD 生成 JAX-WS Web 服务和 JAXB
Type 类,根据 XSD 定义对传入(和传出)消息进行验证。
2、协调器 (Coordinator):为生成的 JAX-WS 前端提供服务的实际实现的
Java 类;协调器将传入消息从其生成的对象图编组成 XML 结构,以便解调器在此基础上进行转换。它可能会充实所得
XML 文档,例如向其注入某种用户凭证属性。然后协调器调用解调器生成内部 XML 结构,随后调用路由器以该输入联络后端服务。协调器让解调器将来自路由器的结果从内部
XML 结构转换成外部结构。然后它可以执行其他充实操作,如对结果执行计算、添加关于服务和请求的元数据、联络其他服务以检索补充数据。最后协调器对
XML 文档进行反编组,将其转换为 JAX-WS 服务类使用的 OO 响应结构并返回。
3、解调器 (Mediator):Java 类,用于将外部 XML(基于服务合同中的
XSD)转换成内部 XML(根据 PL/SQL API 的规定,并且得自于用户定义类型转换的 XML);此类是通用的:它接受并返回
XML 文档且需要 XSLT 样式表作为输入。
4、路由器 (Router):使用 XMLType 参数与 PL/SQL
API 交互的 Java 类;此类还处理交互中的(Oracle 和连接)异常,可选地使用替代后端服务或本地缓存并将技术异常转换成更符合逻辑的故障,这样可以不向服务使用者泄漏任何无关的实现细节。
在本文其他地方我们将看到,当使用类似 Oracle SOA Suite
或 Oracle Service Bus 的 ESB 产品时,如何确定同样的这些阶段,以及在该情况下如何只需远远更少的编程量,因为适配器和
ESB 基础架构提供了大多数现成的功能。
实现数据 Web 服务
上述 Stuff 架构中 Web 服务的实现始于服务合同,它包括一个描述接口(即端口类型)的
WSDL 文档、各种操作和消息(输入、输出和错误)以及详细描述消息的 XML 结构的 XSD。在另一端,它还起始于数据库中的表和
PL/SQL API。
![](images/2013112528.png)
我们来看一个示例:Jukebox 服务。该服务提供一项操作:queryForCDs。此操作将接受
SOAP 请求中的 CDQuery 输入元素,然后将在 SOAP 响应中回复 CDCollection
元素。该服务由 JukeboxService.wsdl 中的合同和关联的 MusicalTypes.xsd
来描述。
![](images/2013112529.png)
输入和输出元素中的 XML 结构在 XSD 文档 MusicalTypes.xsd
中定义。CDQueryRequest 输入和 CDQueryResponse 输出消息的各组成部分通过此
XML 模式定义中的 CDQuery 和 CDCollection 元素来描述。
![](images/20131125210.png)
Web 服务的另一端是数据库,包含几个相关的表:
![](images/20131125211.png)
JukeboxService 项目附带的 PL/SQL API 通过程序包规范和一些用户定义类型来描述:
![](images/20131125212.png)
下面的四个步骤构成实现 JukeboxService 的过程
1、生成 Java Web 服务
2、创建调用 PL/SQL API 的路由器
3、创建带 XML 转换的解调器
4、创建协调器
下面我们逐步完成该实现。
1. 生成 Java web 服务
使用 JDeveloper 中的向导,基于定义 Web 服务合同的 WSDL
和 XSD 生成一个 Java Web 服务实现。
![](images/20131125213.png)
运行该向导并完成生成之后,得到一些生成的类 — 以及一个挂钩点,我们必须在此提供
Web 服务功能的实际实现。
![](images/20131125214.png)
此时,我们将添加一行代码来调用 Coordinator 类(留待第 4
步中开发)。
![](images/20131125215.png)
下图显示此时我们在实现过程中的位置:
![](images/20131125216.png)
该 SOAP Web 服务的 Java 前端已经就位。但它现在还不能转到任何其他地方,而且除了将
XML 请求反编组成 OO 结构之外什么都没干。注意:现在可以部署此 Web 服务,甚至还可以调用它。不过,因为生成的方法
queryForCDs(同名的 Web 服务操作的实现)始终返回 null,响应将始终为空。
2. Router 类调用 PL/SQL API(其包装器)
Java 应用程序将调用 Stuff Music 数据库中的 PL/SQL
API 来处理 CD 搜索请求并返回满足该请求的 CD 集合。该 PL/SQL API 以用户定义类型的形式指定,架构团队决定使用
XMLType 进行 Java 实现与 PL/SQL API 之间的交互。这意味着我们需要在 PL/SQL
API 外添加一层薄的包装器,如下所示。
![](images/20131125217.png)
使用 XMLType 参数重载 search_for_cds 过程的实现非常简单和直接:
![](images/20131125218.png)
XMLType 输入参数 p_cd_query 由 XMLType 上的
toobject 操作转换成同等相应类型。所提供的 p_cd_query 的 XML 结构正好满足此转换的需要,toobject
的结果将会是 cd_query_t 的一个实例。注意:只需对 cd_query_t 的一个实例执行相反的操作,即可轻松了解所需的
XML 结构:
![](images/20131125219.png)
产生的 cd_collection_type 由作用于单个对象类型的 XMLType
构造器转换成一个 XMLType 实例。因为 XMLType 无法基于 TABLE OF <Type>
进行实例化,所以将 cd_collection_type 包装在 jukebox_t 中。search_for_cds
过程返回的 XML 结构如下所示:
![](images/20131125220.png)
注意:在 Java 客户端中使用 XMLType 可能略微复杂,因为这需要在应用服务器中可以使用特定的
Oracle JDBC 和 XDB 库 — ojdbc6.jar 和 xdb.jar。对于更直接、麻烦更少的实现,使用原型通过
String 变量在 Java 与 PL/SQL API 之间进行通信,这么做可能更简便;这些 String
变量是 XMLType 的“序列化”并且包含整个 XML 文档。此方法意味着需要引入另一个更薄的包装器包装
PL/SQL API,该包装器将 XMLType 转换成其 String 表示,反之亦然:
![](images/20131125221.png)
Router 类在 Web 服务实现中的任务很简单:它使用 PL/SQL
API 指定的结构形式的 XML 文档调用该 API,并且同样以 XML 格式并按照该 API 指定的结构接收一个响应,如图所示。
![](images/20131125222.png)
Router 类中的主要方法是 callMusicAPI。该方法是通用的:它并不关心在
Music API 中调用的操作以及传递给它或由它转发的数据。它只是接受一个 (DOM XML) Document
作为输入并返回一个 Document 作为结果。它还接受一个包含对 Music API 的确切调用的字符串。该方法使用
JDBC 数据连接调用从辅助类 ConnectionManager 检索的存储过程(在此不作详细说明)。该方法还依赖于两个辅助方法来将输入
Document 转为 String 并从 MusicAPI 返回的 String 创建一个 Document。
![](images/20131125223.png)
需要间接利用 PL/SQL API 搜索 CD 的 Java 使用者可调用公共方法
searchForCds。实现过程第 4 步中所讨论的 Coordinator 类将是其中之一。
注意,Router 类必须处理一些异常,有些异常与所有调用者甚至都不了解的后端系统(Oracle
数据库中的 PL/SQL API)有关,这些异常可通过调用回溯服务或使用辅助缓存来解决。其他则与传递给此方法的文档有关。
![](images/20131125224.png)
MusicRouter 类的生产版本需要确定如何处理异常,以及关于这些异常该如何向使用者报告(如果需要话)。
3. 创建带 XML 转换的解调器
解调器的任务简单、单一:它需要转换 XML 文档,将其从作为 JukeboxService
合同一部分发布的外部结构转换成从 PL/SQL API 的用户定义类型派生的内部 XML 结构,反之亦然。
![](images/20131125225.png)
协调器(参见下一步)将调用解调器对其所接收的请求执行转换并使用转换结果从路由器获取
CD 搜索结果。然后该结果通过解调器转换成所需外部 XML 结构。
MusicMediator 类本身有一个通用方法,该方法接受并返回一个
XML 文档,并以一个 XSL-T 样式表资源的位置作为输入参数。该类有两个专用方法作为它向协调器提供的两个特定转换;这两个方法调用此通用方法,指示特定样式表。
![](images/20131125226.png)
显然,该解调器的真实逻辑在样式表本身中。这里有外部和内部 XML 结构的映射
— 有向外界发布的规范语言与直接从数据库 API 派生的内部语言之间的分离。
![](images/20131125227.png)
4. 创建协调器
最后,由协调器将一切汇总起来。
![](images/20131125228.png)
MusicCoordinator 类提供 Web 服务的实现。生成的类
JukeboxQueryProcessorImpl 派生自 WSDL 服务合同,其中有一行是手动添加的,该行包含对
MusicCoordinator 的调用。
![](images/20131125229.png)
MusicCoordinator 类中的 queryForCDs 方法的任务是实现
Web 服务合同中所定义的 queryForCDs 操作。此方法由 CDQueryType 的一个实例调用,该类由向导生成并通过
JAXB 映射至 XSD 文档中的 CDQueryType 复杂类型。
cdQuery 对象被编组成 XML 文档。该文档再传递给 MusicMediator
以便转换成 cdQuery 的内部 XML 结构。然后调用 MusicRouter 来接收一个 Jukebox
文档:这是一个 XML 文档,内含通过数据库中的 PL/SQL API 检索到的 CD 详细信息。此文档需要在
MusicMediator 中转换成由 Web 服务的 XSD 中的 CDCollectionType
定义的 XML 结构。最后,此文档反编组成 CDColllectionType 类以及相关的 CD 和曲目对象的一个实例。
![](images/20131125230.png)
此时,在验证和内容充实方面 MusicCoordinator 未做任何事情,而这些
ESB 架构模式中的角色它可以轻松承担。例如,在编组 CDQueryType 之后,协调器可以对 CDQuery
请求执行严格的 XSD 验证,或者使用 Schematron 验证以运用甚至更复杂的规则。调用路由器之后,还可以调用其他路由器以提供其他部分数据,以便可以添加到将要返回给服务调用者的
CDCollectionType。
注意:编组 CDQueryType 和反编组 CDCollectionType
要求在这两个类中均添加批注 @XmlRootElement。
![](images/20131125231.png)
编组操作本身是在以下方法中完成的:
![](images/20131125232.png)
类似地,取消编组是在以下方法中执行的:
![](images/20131125233.png)
实践检验
布丁好坏,不尝不知。同理,对于此 Web 服务实现,需要将其部署到 JEE
应用服务器,随后调用该服务实际处理一个 CD 查询请求并返回一个 CD 集合响应(在 Stuff Music
数据库的支持下)。
当在 JDeveloper 中进行开发时,要运行 JukeBoxService
Web 服务,只需轻松地在应用程序导航器的 JukeboxQueryProcessorService 节点的上下文菜单中激活
Run 选项:
![](images/20131125234.png)
这将启动集成的 WebLogic Server(如果它尚未运行)并将 JukeboxService
应用程序部署到该服务器。
![](images/20131125235.png)
现在您可以调用该 Web 服务进行测试。对此,最简单的做法是,单击控制台中显示的
URL。这将显示 JDeveloper 中的 HTTP Analyzer 工具,将允许您对 JukeboxService
执行 SOAP 调用。
或者,您也可以使用 SoapUI 这样的工具来调用该 Web 服务,如下所示。
![](images/20131125236.png)
因为前面创建的 ESB 架构模式的实现不包括监视或日志功能,所以无法跟踪
Web 服务内部对请求的处理。我们可以看到从 Web 服务返回给我们的响应:CD 集合,并且只能假定内部处理是按照设计正常执行,过程中没有出现瓶颈。提供对服务请求处理的洞察以及用于分析性能、瓶颈和异常的工具,这通常是
ESB 产品具备的功能。
测试灵活性
对于上述 Jukebox 服务的实现,它是不是确实像建议的那样灵活?各阶段之间的封装是否有效?架构是否允许修改服务?
甚至无需试验,很明显就可以看出数据库表结构中的更改完全被屏蔽在视线之外:Web 服务的 Java 实现无法绑定到表的结构(或者甚至其存在),因此对于表的修改严格限制于本地。同样的情况适用于基于搜索参数检索数据的
PL/SQL 代码:只要输入和输出参数的定义未发生更改,PL/SQL 代码如何完成自身的任务对于 Java
实现毫无影响。
我们来看一下其他几个修改。
添加搜索条件
如果我们希望服务的使用者同时能够搜索 CD 上曲目的名称,会怎样?对此,我们需要修改作为 Web 服务合同一部分的
XSD 中的 CDQueryType。需要重新生成 Web 服务的 Java 实现,或者至少需要扩展类
CDQueryType。
在架构的另一端,必须向 cd_query_t 用户定义类型添加一个曲目标题的属性。当然,必须修改 PL/SQL
API 内部的查询逻辑(过程 search_for_cds)以利用该类型中的这一新属性。
最后,需要用新的搜索元素 TrackTitle 扩展将 CDQueryType
文档转换成具有新元素的内部 CDQuery 消息的 XSL-T 样式表。
![](images/20131125237.png)
包含 CD 的其他属性
返回的 CD 唱片可以通过包含发行 CD 的唱片公司的名称或 CD 封面的缩略图来增强。此更改将需要修改
XSD 文档中的 CD 类型。随后重新生成 Web 服务或手动向生成的 CD 类添加属性。
根据 CD 中此新元素的值是源于数据库还是某个新引入的服务,需要进行以下更改:
基于数据库的属性:用新属性扩展数据库类型,扩展 PL/SQL API 中的过程
search_for_cds 中的代码以设置该新属性的值,并通过添加对 RecordCompany 元素的支持扩展将内部
CD 集合转换成公共 CD 集合 XML 结构的 XSLT。
通过充实,修改 Coordinator 类以调用诸如 Amazon Web
服务以获取唱片公司的名称或 CD 封面的缩略图并在转换为外部格式之后将其添加到响应 XML(CD 集合文档)。注意:在此场景中,对解调器、路由器或数据库代码没有影响。根据第三方服务调用方式的不同,可能引入新的
Mediator 和 Router 类。
向服务添加操作
可以使用新的操作(如 queryForMovies、getCDDetails 或 addCD)对 Jukebox
服务进行扩展。新操作可能需要在所有层上进行更改,从生成的 Java Web 服务到需要提供新操作部分功能的
PL/SQL API。除了 XSL-T 样式表,无需创建新对象,但有几个对象需要扩展。
首先,需要扩展 WSDL 可能还有 XSD 以便包含新操作及其参数的描述。其次,需要重新生成 Java
Web 服务。
可以选择根据 PL/SQL API 是否已经包含具有新操作的基本功能的过程,向 PL/SQL API
程序包添加 PL/SQL 过程,为此过程的输入和输出参数创建用户定义类型,然后创建执行 XMLType
到用户定义类型映射以及 XMLType 到 String 转换的包装器。
向 Router 类添加方法以调用支持新操作的新 PL/SQL 过程。
下一步需要创建 XSLT 以便将传入请求消息转换成可以传递给 PL/SQL API 的内部 XML 结构,以及将
XML 输出转换成公共响应消息。
最后,在 Coordinator 类中创建一个方法,该方法可调用解调器进行转换,还可调用 Router
类来调用 PL/SQL API 上的所需服务。
向 Jukebox 服务添加安全性
添加安全性:例如,我们应该对 Jukebox 服务应用身份验证和授权,因为我们不能让任何人都能调用该服务器,为此,我们需要实现这种验证和授权需求。无需在
Jukebox Web 服务应用程序中更改一行代码,即可对其应用安全策略。如果希望 Jukebox 服务仅对通过身份验证的各方用户(具有特定角色)可用,可以在应用服务器中向其附加安全策略。于是,对该服务的任何调用均会由应用服务器进行身份验证。用户身份及其关联角色在服务器使用的任何用户目录中定义。
Oracle Service Bus 让生活更轻松
Stuff, Inc. 团队构想的架构是可行的。它通过以上示例所讨论的实现证明了自己。它提供了灵活性、可伸缩性、封装和分离,并最大程度利用了现有的数据库开发技能。不过,它需要不少手动操作,而且在监视和管理方面此架构和工具提供的功能很少。
当 Stuff, Inc. 了解到他们将快速扩展其 Web 服务产品系列,添加服务和服务使用者时,他们重新评估了原来的实现,并决定引入
Oracle Service Bus。此决策的主要推动因素是期望获得更高的工作效率并且减少对 Java
编程技能的依赖。此外,Stuff 的管理员有点疲于应付他们已提供的 Web 服务的运行责任。他们希望有一些工具来监视服务活动和帮助分析问题。
结果发现在使用 Oracle Service Bus 时,最终为数据服务设计的架构仍然非常有效。VETRO
阶段仍然存在,虽然实现方式稍有不同。在 OSB 中的标准工具的帮助下,代理服务执行了大部分的验证、充实、转换和路由工作,而业务服务则利用数据库适配器调用
PL/SQL API。注意,此适配器能够很好地与用户定义类型交互,这意味着不再需要数据库中的 XMLType
包装器。基于用户定义类型的 PL/SQL API 可以直接使用。
![](images/20131125238.png)
OSB 代理服务和业务服务取代了先前自定义 Java 实现中的协调器、解调器和路由器的
Java 类。不过,解调器使用的 XSL-T 转换可以在 OSB 的代理服务中得到重用。协调和路由通过声明方式进行配置并由
OSB 基础架构执行。
![](images/20131125239.png)
路由节点调用业务服务 — JCA 数据库适配器,该适配器代表代理服务 JukeboxServicePS
调用 PL/SQL API。请求管道上的 Replace 操作将 CDQuery 请求转换成业务服务所需的
XML 结构。响应管道(路由节点右侧)上的 Replace 操作将响应从业务服务转换为代理服务应遵守的
WSDL 和 XSD 合同中定义的 CDCollection 结构。
使用 OSB 的整个实现可以描述如下:
![](images/20131125240.png)
本文附录中描述了使用 Oracle Service Bus 实现 JukeboxService
的详细步骤。
Stuff, Inc. 团队非常满意地看到他们设计的架构对于 ESB 模式的自定义代码实现与基于 ESB
产品(如 Oracle Service Bus)的实现一样有效。对开发人员而言,看到 PL/SQL API
在 Oracle Service Bus 中也能够得到充分利用,甚至 XSL-T 样式表也可以大体上得到重用,他们觉得自己的工作很有价值。
该组织在大约三个月前开始引入 Oracle Service Bus。Stuff 的员工现在报告说服务实现团队的工作效率得到提高,并且管理员有了更多信心和更高的运行效率。
总结
许多组织普遍存在这样的需求:向内部和外部使用者发布基于企业数据库的服务。可以构造这类服务的各种架构设计和实现。本文介绍了一家组织的一种数据服务的决策过程、技术设计和实现。注意此组织(在此称为“Stuff,
Inc.”)代表了大量具有类似需求的、已经受益或可能受益于类似实现的组织。
Stuff, Inc. 的数据库开发技术非常具有代表性。PL/SQL API 是许多应用程序和服务实现的基础,也是此类实体与数据库交互的唯一方式。任何
SQL 都不能在该 API 之外执行。为了最大程度减少服务器往返次数,在 PL/SQL API 中提供了各种基于内部其他更细粒度的过程的组合操作。
为应对 Stuff, Inc. 架构团队所面临的挑战,他们研究和应用了企业服务总线设计模式。采用了自定义
Java 方法来实现以下四个阶段:Web 服务接口(使用 JAX-WS 和 JAXB 生成)、协调器(用于验证、充实以及激活解调器和路由器)、解调器(用于
XML 消息转换)和路由器(用于与 PL/SQL API 交互)。这些阶段一起实现了 ESB 文献的 VETRO
模式。该设计的中心思想是严格分离、基于接口的交互、逻辑封装和广泛的灵活性以满足不断变化的要求。
本文介绍了如何根据这个四阶段方法来实现 Jukebox 服务,并演示了此实现如何满足各种变化的要求。最后,本文最后说明了引入
Oracle Service Bus 对具体 Web 服务的实现和整体架构的影响。结果发现,对架构和设计的影响非常小。Oracle
Service Bus 基础构架可以接受许多通过自定义代码另行实现的功能,且使用数据库适配器可大大降低与
PL/SQL API 交互的复杂性。 |