在现在的企业应用程序的开发中,Web 服务已经越来越普遍。然而,从传统意义上来说,它们还没有达到和所支持的服务相同的水平。当构建 J2EE 应用程序,特别是事务服务的时候,企业依赖于这些服务。本文概述了事务服务是如何在一个使用 Java Transaction API 的 J2EE 环境中的 Web 服务事务的帮助下,与 Web 服务实现无缝连接的。
本文简要地概述了这项新的 Web 服务技术和已被证实的传统的事务技术,解释了它们是如何能够跨分布式的 J2EE 环境甚至跨不同的事务体系结构来实现互操作的。
本文假设您已经对事务服务的概念(例如,ACID properties、提交/回滚、事务划分,等等)的理解达到中级水平。要想了解事务服务的进一步信息,特别是 JTS,请参考文章 Java theory and practice:Understanding JTS —— An introduction to transactions。这篇文章可以在 developerWorks 上找到(请参阅 参考资料)。同样,我也想要推荐一本关于事务的更全面信息的好书,它就是由 Philip Bernstein 和 Eric Newcomer 合著的 Principles of Transaction Processing(请参阅 参考资料)
什么是 Java Transaction API(JTA)?
JTA 是事务服务的 J2EE 解决方案。本质上,它是描述事务接口(比如 UserTransaction
接口,开发人员直接使用该接口或者通过 J2EE 容器使用该接口来确保业务逻辑能够可靠地运行)的 J2EE 模型的一部分。
JTA 具有的三个主要的接口分别是 UserTransaction
接口、 TransactionManager
接口和 Transaction
接口。这些接口共享公共的事务操作,例如 commit()
和 rollback()
, 但是也包含特殊的事务操作,例如 suspend()
, resume()
和 enlist()
,它们只出现在特定的接口上,以便在实现中允许一定程度的访问控制。例如, UserTransaction
能够执行事务划分和基本的事务操作,而 TransactionManager
能够执行上下文管理。本文仅仅需要您对 JTA 有一个基本的了解。
JTA 是一个定义明确的事务服务,向 J2EE 应用程序开发人员提供一种可以直接使用的服务。作为选择,一个应用程序也可能这样部署,容器将代替开发人员来管理事务行为。在后一种情况下,开发人员能够全神贯注于他们的应用程序的业务逻辑,同时由 J2EE 容器来负责事务逻辑。
模型明确的事务服务的好处是对于每个单独的事务总是维持四个 ACID 特性。尽管这是一个实现相关的问题,WebSphere Application Server 提供为每个导入的或者导出的事务保护这些 ACID 特性的能力,而不管并发的事务数目是多少。
经历过所有的事务体系结构,想要有效地将一组事务传送给其他并不共享同样模型的事务服务,同时保持原子的工作单元,是非常困难的。在我们的案例中,建模的 JTA 运行在 Java Transaction Service(JTS) 之上,JTS 处理输入和输出事务传送的请求。
因为 JTS 是一种由 CORBA 定义的对象事务服务(OTS)的 Java 实现,它只能够与另一个 OTS 模型连接。因此, 一个事务只能传送给另一个 OTS-兼容的目标,典型地即另一个 J2EE 实现。因为 JTA 和 JTS 规范没有对这些接口的底层实现加以限制 (只要它们符合模型),事务可以安全地在两个 J2EE-兼容的应用程序服务器之间传送,而没有丢失它们的 ACID 特性的风险。然而,J2EE 服务器并不必须处理非 J2EE 调用。
某些 J2EE 服务器可能是例外;例如,WebSphere Application Server 将正确地处理一个与 CORBA 兼容事务相关联的输入的 CORBA 请求,将这个事务传送给线程,然后在它的上下文里执行事务工作。然而,在大多数情况下,当您试图在事务模型之间移动的时候,您不得不超越 JTA 和 JTS,把目光投得更远,在这里 Web 服务出现了。
Web 服务是一种能够作为应用程序一部分部署在可访问的服务器上供内部和外部客户使用的对象。Web 服务由它的 Web 服务描述语言(WSDL)来描述。它定义了一个使用基于 XML 调用(典型地使用 SOAP 协议)的 Web 服务的输入和输出参数的用法。例如,客户端可以查看已经由服务器发布的 WSDL,然后构造客户端代码来调用 Web 服务。一旦完成,它就能够通过将 SOAP 消息传递给 Web 服务的一个方法来调用它。在这条 SOAP 消息中包括诸如方法 名称的信息以及任何它所需要的参数。返回值将在另一条 SOAP 消息里被传送回来,再由客户提取出来。
Web 服务由哪种语言编写而成并不重要,因为 WSDL 没有定义语言或者编程的模型相关的细节(例如,Java 和 J2EE 技术)。这就给了 Web 服务的作者和客户端的作者选择他首选的解决方案 的灵活性。
让我们来比较一下 Web 服务和 Enterprise JavaBean(EJB)组件。EJB 组件要求 RMI-编译的代码,以便使客户端能够访问,所以 它能够像它的代理一样创造本地的存根(stub)对象。因此,这将需要在每一次它们改变的时候,向所有的客户端重新分配存根(stub)。 无论如何,和 Web 服务一起您将使用 WSDL,所以客户端能够构造它们自己的客户端调用代码,在本地类路径上不需要服务器的类来执行调用。这个模型提供了一个非常巧妙的方法调用过程。 EJB,作为 J2EE 模型的一部分,必须使用 Java 客户来调用,最好是一个 J2EE 管理的客户端。另一方面,Web 服务可以被任何客户端代码所调用,这个代码能够构造一个结构良好的 SOAP 请求。因而,举例来说,一个部署在 J2EE 服务 器上的 Web 服务能够使用 C++ 客户来调用。
因为 Web 服务请求(通过 HTTP 的 SOAP)的性质与其他的方法调用(例如,一个使用通过 IIOP 的 RMI 的 EJB 调用)差别很大,支持执行分布式事务的代码直到最近才可获得。这已经成为在 使用 Web 服务作为分布式事务企业应用程序一部分时,主要的问题。本质上,Web 服务不能运行在 Web 服务调用之前开始的事务上下文 中,也不能将一个事务上下文传送给另一个组件。
如果 Web 服务被用于工业,必须确保它们在事务环境 中运行的时候,以可靠的和可预知的方式工作。直到现在,Web 服务只能够使用独立于其他组件的事务——在 Web 服务的方法范围里划分的 和服从它的底层的事务实现的规则——并且物理上不能离开 Web 服务或者进入另一个 Web 服务。企业应用程序具有始终在企业组件间流动 的事务。这需要成为 Web 服务的标准来确保它们能够被正确地使用,通过利用 Web 服务的功能仅仅忽略在我们的所有严格的企业应用 程序中依赖的和使用的事务支持来避免改变您的编程风格。
解决方案就是一种称为 Web 服务事务(WS-Transaction) 的新技术。它能够调整事务的上下文。这个上下文可以被 Web 服务、其他的诸如 EJB 的 J2EE 组件、甚至其他支持 WS-Transaction 的 非 J2EE 事务服务使用。
WS-Transaction 是一个规范。它扩展了 Web 服务协调(WS-Coordination)规范来定义一种支持原子事务的协调。
WS-Coordination 是一个协调框架来使分布的参与者 能够在他们个体行动之上就一个通用的结果达成协议。
本质上,这意味着分布式的参与者(例如,在不同机器上的两个应用程序服务器)将能够使用 WS-Coordination 把每个参与者 的行为集在合一起,进一步地,并且通过确保它们完全同意对于在这个协调上下文里它们各自执行的所有行为均产生单一的结果,来 进一步管理这些行为。否则,则不能以一个受控的方式来完成这些功能。
协调上下文可以被看作是一个标识符,行为执行在这个标识符之下。作一比较,这个概念非常类似于事务上下文。当事务工作完成, 在事务上下文里管理它,当调用这个上下文去确定或会滚时这个工作完成。协调上下文包含的附加信息是一个协调标识符、关于协调类型的 详细资料以及包括端口信息以便协调服务能够被访问的协调协议。在下面定义了这些术语。
协调服务,或者 协调器(Coordinator), 进一步由三个服务组成: 激活服务(activation service)、 注册服务(registration service)和 协调协议(coordination protocol) 服务。激活服务支持 CreateCoodinationContext
操作来允许新的协调上下文存在。注册服务支持 Register 操作来允许参与者 在协调上下文中执行工作。协调协议服务支持协调协议的使用,这个协议定义了协调器(Coordinator)和参与者之间的行为和通信。
协调类型是一个协调行为的固定的集合,这个集合详细说明了协调协议的集合以及协调器(Coordinator)应该如何驱动完成。 WS-Transaction 规范描述了两个协调类型—— 原子事务(Atomic Transaction)(AT)和 业务协定(Business Agreement)(BA)。 这些协调类型中的每一个都包括协调协议。例如,原子事务(Atomic Transaction)协调类型包括像 two-phase commit protocol(Durable2PC)和 phaseZero protocol(Volatile2PC)这样的协调协议。 您可以希望在支持原子事务的环境中使用这两个协议。
业务协定(Business Agreement)协调类型提供了一种不同的功能类型。它被设计成用于更长的时帧。而不像原子事务,正常地您 与它联系一个非常短的生命期。业务协定协议(Business Agreement protocol)的一个例子就是它自己,被称作业务协定(Business Agreement) 它是一个补偿协议。
WS-Coordination 和 WS-Transaction 之间是什么关系?
WS-Coordination 是基本的框架,使参与者之间活动的分布式结果成为可能。WS-Transaction 定义了协调类型,例如原子事务(Atomic Transaction),协调类型使用 WS-Coordination 框架来定义规则。在协调器(Coordinator)和参与者通信时,它们必须遵循这些规则。两者之间的这个区别很重要。
两个应用程序和一个协调器(Coordinator)之间主要的协调流程如下面的 图 1所示。
![图 1. 基本协调流程](https://i-blog.csdnimg.cn/blog_migrate/00bff2ec9a7636e8c9474da033107348.png)
- App1 向在协调器上的激活服务提出一个请求。
- 协调器开始一个新的活动,使用它的
CoordinationContext
(协调器的 XML 消息)来对 App1 做出响应。 - App1向注册服务提出请求来注册使用协调协议X。
- App1 以它期望的方式调用 App2,传递
CoordinationContext
给协调器。 - App2 向注册服务提出请求(使用诸如端口信息的参数,它们 可以在 App1 传递的
CoordinationContext
中找到)来注册使用协调协议Y。 - App2结束它的工作,将控制返还给 App1,活动结束。
- 协调器使用协议 X 类型消息响应 App1。
- 协调器使用协议 Y 类型消息响应 App2。
在一个现实世界的情况中,Web 服务可能是事务的和分布式的,协调器的发起者( App1)将 CoordinationContext
传递给任何它所期望的活动中的参与者( App2)。这个上下文的接收者有两种选择:它们可以使用已经创建好了的协调器( Ca),或者如果它们愿意,也可以在初始的 CoordinationContext
中传递创建的新的协调器。然后,第二种选择将新的协调器( Cb) 作为 App2的代理协调器。它将包括与协调器 Ca相同的活动标识符,但是当 App2向它的协调器 Cb注册 Durable2PC 协议的时候,它的请求直接传送给了协调器 Ca。 类似地,在结束时,准备和提交消息在最终到达 App2(它已经注册过 Durable2PC 协议)之前将从协调器 Ca传递给协调器 Cb。
请参阅 WS-Transaction 规范的 4.1 节 AT3.1 Example Atomic Transaction Message Flow,在那里您将看到一个应用程序和调解的协调器之间的 WS-Coordination 流程的非常好的示例(请参阅 参考资料)。
Web 服务事务:原子事务(WS-AtomicTransaction)
WS-AtomicTransaction 是一种对于原子事务的特殊的协调类型,它提供了一组协调协议。这些协调协议是:
- Completion
- CompletionWithAck
- Volatile2PC
- Durable2PC
- OutcomeNotification
当协调上下文创建以后,协调类型被指定,但是协调协议直到注册时才被指定。任何参与者可以注册任意数目的协调协议,应该发送和接收 由协议定义的恰当的消息。例如,如果一个参与者在协调器中注册了 Durable2PC 协议,当完成时一条准备消息将被发送给这个参与者,它们将被认为以与正常的事务资源相似的方式投票。想要了解这里每个协议的信息和它们的状态图,请查阅 WS-Transaction 规范, 第 4 节 AT3 Coordination protocols(请参阅 参考资料)。
如何能将 JTA 事务和 WS-AtomicTransaction 一起使用?
因为 JTA 和 JTS 是实现相关的,我将使用的这个示例是 WebSphere Application Server V5.0.2 和 WS-Transaction Tech Preview。这个场景将有两台机器,每个上都运行有应用程序服务器,如 图 2 所示。 应用程序服务器A部署并运行一个 Bean Managed Transaction(BMT)EJB 组件。应用程序服务器B部署并运行一个 Web 服务。 EJB 组件通过使用 JTA 提供的接口 UserTransaction
开始一个事务。它对 XA-compliant database 执行事务工作(步骤 1),然后使用 SOAP/HTTP 向在应用程序服务器B上的 Web 服务发送一个请求(步骤 2)。Web 服务对 XA-compliant database 执行工作(步骤 3),然后返回到 EJB 组件(步骤 4),由它再次使用 UserTransaction
接口来提交事务。所有由 EJB 和 Web 服务对数据库执行的事务都已经被包含在一个活动的范围里,这个活动是由协调器恰好在调用 Web 服务(步骤 2)之前创建的,它已经被提交,同时保存着所有的 ACID 特性,它就好像是单一的工作单元。
让我们来看看下面的两个领域——J2EE 领域和 Web 服务领域。在 J2EE 领域里,使用的事务模型是 JTA。在 Web 服务领域里, 使用的事务模型是 WS-AtomicTransaction。WebSphere Application Server 把一个 Java Web 服务看作是一个 J2EE 对象,因此也就 意味着,Web 服务的实现属于 J2EE 领域,而调用属于 Web 服务领域。在 WebSphere 领域,正确地驱动协议总是正在被使用的模型 (JTA 或者 WS-AtomicTransaction)的责任。
图 2 展示了 在一个事务企业应用程序中包含 Web 服务是多么的容易,同时也展示了对于没有费一行代码麻烦就在导入的事务上下文中运行这个 Web 服务的用户来说,它又是多么的无缝。
![图 2. 使用 JTA 事务和 WS-AtomicTransaction 事务](https://i-blog.csdnimg.cn/blog_migrate/7d45a4191a92d9bb2065635915d51bc2.png)
请注意:The EJB 组件正运行在一个受管理的环境中(EJB 容器)并且 Web 服务是符合 JSR 109。
WS-Coordination 依靠它的基于XML的调用来 利用它本身是 Web 服务的优势。因为用来调用 WS-Coordination 操作的协议是 SOAP,消息内容是 XML 格式的纯文本。这意味着,当使用 HTTP 传递给 Web 服务时,将不能仅仅通过 SOAP 包本身来确定客户的详细资料,例如编程语言。因此,WS-AtomicTransaction 将能够与任何其他的使用任何支持 WS-AtomicTransaction 的编程语言编码的事务服务相连接。
在近来的一个由 IBM 和 Microsoft 主办的 Web 服务演示上,展示了 WS-AtomicTransaction 的这个跨事务服务和编程语言的互操作性。 图 3 展示了一个示范这项技术的场景。
在 图 3 中有一个.NET 服务器开始一个非 JTA 事务,向两个 WebSphere 应用程序服务器和另外一个.NET 服务器提出了 Web 服务调用请求。每个应用程序服务器都使用它们的底层事务服务来执行事务工作。每次您能够使用 WS-Transaction 调用一个您将转到的 Web 服务。当发起者完成事务,您使用 WS-Transaction 技术来协调每个参与者,确保它们都已完成,就好像它们是单一的工作单元似的。
![图 3. 在 Steve Mills 和 Bill Gates 的 Web 服务演示中的一个 WS-AtomicTransaction 场景的示例拓扑。](https://i-blog.csdnimg.cn/blog_migrate/d3979f1dec749c8c70fee9699e380a6c.png)
在本文中,您已经了解到 WS-Coordination 和 WS-Transaction 的基本概念。到现在为止,Web 服务还不能在分布式环境里使用事务。WS-Transaction 允许 Web 服务执行事务工作,这个事务工作作为更广泛的活动生成组件、应用程序服务器、甚至实现的一部分,正如在 IBM 和 Microsoft Web 服务演示中所展示的。
在 WS-Transaction 的支持下,我们能够可靠地使用 Web 服务作为我们的企业应用程序的一部分,因为它已经为事务支持嵌入到其他的企业组件里。