原文链结: http://www.theserverside.com/articles/article.tss?l=BPELJava
BPEL 的作用
实现从面向过程到面向服务的转变需要一种语言以描述 Web services 是怎样被组织成业务流程。如果这种描述是可执行的,即允许我们定义抽象的流程,而且允许我们描述流程准确的执行规则,那将更好。而 BPEL 正是这样一种语言。事实上它是最先具备以下特性的语言:
1 允许我们定义抽象和可执行的流程
2 有大多数公司支持
3 软件运行在 bpel 流程可以执行( BPEL 服务器)和设计( BPEL 设计器)的平台上
在我们对 BPEL 做更深入的了解之前,先论述一下怎样组织 web 服务。这通常有两种方法:音乐演奏式和舞蹈式。音乐演奏式为一个中心进程控制相关的 web services 并协调在操作中被调用的 web services 中不同操作的执行。音乐演奏时的乐谱就是一次组织过程。被调用的 web services 并不知道他们被调用以组织成一个流程,也不知道他们是一个更高层业务流程的一部分(它们也不需要知道)。只有音乐演奏中的指挥者知道这些,所以音乐演奏方式是将清晰定义的操作和 web services 的调用顺序集中起来管理的方式。
相比而言舞蹈方式不依赖一个中心的协调器。每一个在舞蹈方式中被调用的 web service 清楚的知道何时执行它的操作并且知道与谁合作。舞蹈方式是专注与信息交互的合作方式。所有的参与者需要关注业务流程,操作的执行,信息的交互以及信息交互的时机。
通过对组合 web services 以执行业务流程的了解,音乐演奏方式比之舞蹈方式为更灵活的处理方法:
我们准确的知道谁对整个业务流程的执行负责
即使是那些不知道他们是一个业务流程一部分的 web services ,我们也可以组合
当错误发生时我们也可以提供可选择的替代
BPEL 遵循音乐演奏的方式。舞台方式为其他标准采用,比如 WSCI ( Web Services Choreogaphy Interface )和 WS-CDL ( Web Service Choreography Description Language )。比之 BPEL ,舞蹈方式还没有获得业界的支持。
2002 年 8 月, BEA 、 IBM 、 Microsoft 开发出 BPEL 的第一个版本。从那时候起,越来越多厂商的加入使得在 2003 年 3 月在第一个版本基础上做了一些调整和改进的 1.1 版本的诞生。在 2003 年 3 月, BPEL 被提交至 OASIS 组织作为标准,后来 WSBPELTC 组织成立。
BPEL 可以在公司内部和公司之间使用。在公司内部, BPEL 的作用是标准化企业应用集成和促进以前孤立系统之间的集成。在企业之间, BPEL 使得业务伙伴之间的集成更容易更高效。以 BPEL 描述的业务流程的定义在不影响现有系统的情况下完成升级。在已经是函数环境或将要通过 web services 方式提供服务的环境当中 BPEL 是重要的技术。随着 web service 技术得到越来越多的使用, BPEL 的重要性将日渐增强。
BPEL 语言
现在让我们看一下 BPEL 语言。 BPEL 作为一种语言具体设计用来定义业务流程。 BPEL 支持两种不同类型的业务流程:
可执行流程允许我们指定严格的业务流程的细节,他们由音乐演奏引擎执行。在大多数情况下, BPEL 被用作定义可执行的流程
抽象的业务协议允许我们指定仅仅在各参与者之间公共的信息交换。他们不包含处理流程的内部细节并且不是可执行的。
BPEL 建立在 XML 和 web services 之上,它是一种基于 XML 的语言,支持包括 SOAP,WSDL,UDDI,WS-Reliable 消息 ,WS-Addressing,WS-Coordination 和 WS-Transaction 的 web services 技术栈。 BPEL 汲取了两种早先的工作流语言: WSFL(Web Services Flow Language) 和 XLANG 。 WSFL 由 IBM 设计,基于有向的内容。 XLANG 由微软设,是一种程序块结构语言。 BPEL 融合了这两种方法为业务流程的描述提供了丰富的语法。
一个 BPEL 流程严格指定了参与的 web services 被调用的顺序。这可以顺序或并行地完成。使用 BPEL 我们可以表示有条件的行为,例如一个 web service 的执行可以依赖前一个调用的结果。我们也可以构建循环,申明变量,拷贝和赋值变量,定义错误处理程序等。通过组合这些结构,我们可以以一个算法方式定义复杂的业务流程。
因此 BPEL 可以与像 java 这样的一般编程语言相比,不过没有 java 那样强大。但另一方面,它更简单并适合业务流程的定义。因此 BPEL 不是对 java 这样的高级语言的替代而是一个补充。让我们了解一下一个典型的 BPEL 流程。首先,这个 BPEL 业务流程收到一个请求。为了处理这个请求,流程开始调用相关的 web services 并将最后的结果返回给最初的请求发送者。因为 BPEL 流程需要与其他的 web services 通信,所以它非常依赖被合成 web service 所调用的 web services 的 WSDL 描述。
一个 BPEL 流程由很多个步骤组成,每一步骤被称为一个活动。 BPEL 支持基本的和结构化的活动。基本的活动即为基础的结构,用作公共的任务,比如:
使用调用其他的 web services
通过发送一个消息等待客户端调用业务流程使用 ( 收到一个请求 )
使用对同步的操作产生响应
使用处理数据变量
使用指示错误和异常
使用等待一段时间
使用结束整个流程等等
这样我们可以组合这些和其他基本的活动定义准确反映业务流程步骤的复杂算法。为了组合基本的活动 BPEL 支持一些结构化的活动。其中最重要的有:
允许我们定义一系列按顺序调用的活动
用来定义一系列并行调用的活动
用来构建分支结构
用来定义循环
在许多的替代路径中选择一个的操作使用
每一个 BPEL 流程也可以使用申明变量,使用定义合作链接。我们将在文章的下面部分对合作链接作更多的探讨。
一个 BPEL 流程可能是同步也可能是异步的。一个同步的 BPEL 流程锁定客户端 ( 使用这个流程的 ) 直到这个流程完成并返回一个结果给客户端。一个异步的流程不锁定客户端,而是使用一个回调来返回结果 ( 如果结果存在的话 ) 。通常我们使用异步的流程实现长时间的流程,使用同步实现在一个相对短的时间里返回结果的流程。如果一个 BPEL 流程使用异步的 web services ,流程本身同时也是异步的 ( 虽然这不是必须的 ) 。
对于客户端来说,一个 BPEL 流程看起来就和其他的 web service 差不多。当我们定义一个流程,实际上我们是在定义一个由已存在服务组合而成的新的 web service 。为了调用由 BPEL 描述的业务流程,我们需要调用合成出来的复合 web service 。下图为一个 BPEL 流程的示意图:
合作链接
上面我们提到 BPEL 也申明合作链接,现在让我们解释一下什么是合作链接。我们已经提到 BPEL 和外部的 web services 的交互有两种方式:
BPEL 流程调用其他 web services 上的操作
BPEL 流程接收客户端的调用。在所有客户端中有一个是发起最初调用的 BPEL 流程的使用者。其他客户端是 web services 。举例来说,是那些已经为 BPEL 流程所调用,但是需要回调以返回结果。
BPEL 把这些所有和它交互部分的链接称之为合作链接 (partner links) 。合作者链接可以是被 BPEL 流程调用的 web services ,也可以是调用 BPEL 流程的客户端。每一个 BPEL 流程至少有一个客户端合作链接,因为必然有一个调用 BPEL 流程的客户端。
通常一个 BPEL 流程也至少有一个调用的合作链接,因为它将调用至少一个 web service( 通常不止一个 ) 。不管怎么样,被调用的合作链接可能成为客户端链接——这通常是在异步服务的情况下,流程调用一个操作的地方。然后这个服务 ( 合作者 ) 调用流程上的回调操作来返回被请求的数据。
BPEL 像合作链接一样对待客户端有两个原因。最显而易见的是支持异步交互,第二个原因是基于 BPEL 流程可以提供服务的事实。这些通过端口类型提供的服务可以为多于一个的客户端使用。流程可能希望区分不同客户端并仅仅提供给他们经授权的功能。举例来说,一个保险流程可能提供给汽车保险客户与房产保险客户不同的一系列操作。
综上述,我们可以看到合作链接描述了指向合作者的链接,这样的合作者可能是:
流程调用的服务
调用流程的服务
两者兼而有之的服务——它们既被流程调用也调用流程
BPEL 的例子
为了了解 BPEL 流程究竟是什么样子,下面我们给出一个选择最好保险服务的非常简单的 BPEL 流程。首先,我们申明指向一个 BPEL 流程客户端(称作 client )和两个保险 web 服务 ( 称作 insuranceA 和 insuranceB) 的合作链接。
<?xml version="1.0" encoding="utf-8"?>
<process name="insuranceSelectionProcess"
targetNamespace="http://packtpub.com/bpel/example/"
xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:ins="http://packtpub.com/bpel/insurance/"
xmlns:com="http://packtpub.com/bpel/company/" >
<partnerLinks>
<partnerLink name="client"
partnerLinkType="com:selectionLT"
myRole="insuranceSelectionService"/>
<partnerLink name="insuranceA"
partnerLinkType="ins:insuranceLT"
myRole="insuranceRequester"
partnerRole="insuranceService"/>
<partnerLink name="insuranceB"
partnerLinkType="ins:insuranceLT"
myRole="insuranceRequester"
partnerRole="insuranceService"/>
</partnerLinks>
...
然后,我们为保险请求申明变量 (InsuranceRequest) ,保险 A 和 B 响应 (InsuranceAResposne, InsuranceBResposne) ,和最终的选择 (InsuranceSelectionResponse)
...
<variables>
<!-- input for BPEL process -->
<variable name="InsuranceRequest"
messageType="ins:InsuranceRequestMessage"/>
<!-- output from insurance A -->
<variable name="InsuranceAResposne"
messageType="ins:InsuranceResponseMessage"/>
<!-- output from insurance B -->
<variable name="InsuranceBResposne"
messageType="ins:InsuranceResponseMessage"/>
<!-- output from BPEL process -->
<variable name="InsuranceSelectionResponse"
messageType="ins:InsuranceResponseMessage"/>
</variables>
...
最后,我们具体化流程步骤。首先我们从客户端等待初始的请求信息 () 。然后我们使用并行调用 () 两个保险 web 服务。保险服务返回保额,然后我们选择低的保额 (/ ) 并使用将结果返回给客户 (BPEL 流程的调用者 )
...
<sequence>
<!-- Receive the initial request from client -->
<receive partnerLink="client"
portType="com:InsuranceSelectionPT"
operation="SelectInsurance"
variable="InsuranceRequest"
createInstance="yes" />
<!-- Make concurrent invocations to Insurance A and B -->
<flow>
<!-- Invoke Insurance A web service -->
<invoke partnerLink="insuranceA"
portType="ins:ComputeInsurancePremiumPT"
operation="ComputeInsurancePremium"
inputVariable="InsuranceRequest"
outputVariable="InsuranceAResposne" />
<!-- Invoke Insurance B web service -->
<invoke partnerLink="insuranceB"
portType="ins:ComputeInsurancePremiumPT"
operation="ComputeInsurancePremium"
inputVariable="InsuranceRequest"
outputVariable="InsuranceBResposne" />
</flow>
<!-- Select the best offer and construct the response -->
<switch>
<case condition="bpws:getVariableData('InsuranceAResposne',
'confirmationData','/confirmationData/Amount')
<= bpws:getVariableData('InsuranceBResposne',
'confirmationData','/confirmationData/Amount')">
<!-- Select Insurance A -->
<assign>
<copy>
<from variable="InsuranceAResposne" />
<to variable="InsuranceSelectionResponse" />
</copy>
</assign>
</case>
<otherwise>
<!-- Select Insurance B -->
<assign>
<copy>
<from variable="InsuranceBResposne" />
<to variable="InsuranceSelectionResponse" />
</copy>
</assign>
</otherwise>
</switch>
<!-- Send a response to the client -->
<reply partnerLink="client"
portType="com:InsuranceSelectionPT"
operation="SelectInsurance"
variable="InsuranceSelectionResponse"/>
</sequence>
</process>
因为每一个 BPEL 流程都是一个 web service ,每一个 BPEL 流程也需要一个 WSDL 文档。我们将不再对开发 BPEL 流程的更深入的细节作讨论。更多的资料可以参阅由 Packt Publishing 于 2004 年 10 月出版的《 web 服务的业务流程执行语言》 (Business Process Execution Language for Web Services)
BPEL 和 Java
看到从上面 BPEL 流程的例子一些人也许会想这样一个组合用 java 也很容易实现。对于非常简单的流程来说这是正确的。但是对于更复杂的流程来说我们会看到 BPEL 比之 Java 的至少两个重要的优势。
BPEL 比之 Java 的第一个优势是 BPEL 流程是可移植的,甚至可以运行在 Java 平台之外。 BPEL 流程可以在基于 Java 平台的音乐演奏服务器上运行也可以在任何其他的软件平台上运行 ( 如 .Net 平台 ) 。这在使用不同平台的 B-B 交互中显得尤为重要。
BPEL 的第二个优势是它针对业务流程特性的支持。通常业务流程是长时间运行的,特别是他们在 internet 上实现与其他合作者交互的时候。有可能这样流程的执行需要几分钟,几小时,甚至是几天才能完成。有可能它们调用一个 web service 需要等待一个相对长的时间以获得回调的结果。如果我们不使用一个 BPEL 流程而是使用一个 Java 应用程序我们的大部分时间将会担心什么线程已经完成,什么仍然在运行。我们将不得不跟踪 Java 线程以确定那些我们能结束,又有哪些需要继续运行以获得回调结果。
BPEL 也用相对简单的方式支持补偿。对在业务流程中那些已经成功完成操作的补偿,或者撤销操作是业务流程中最重要的问题之一。补偿的目的是恢复这个被撤销的业务流程中已经执行完成的活动。
补偿与大多数业务流程的特性相关,这种业务流程是长时间运行的并且使用异步的方式与松散耦合的 web servcies 通信。就成功完成来说业务流程是非常脆弱的,因为他们所使用的数据本身就是脆弱的。因为它们通常横跨多个合作伙伴 ( 同时是多个企业 ) ,所以需要关注业务流程可能是完整执行也可能部分结果是未完成的,即补偿。这和在企业信息系统中的 ACID 事务类似。 BPEL 使用定义的补偿操作的能力支持补偿的概念 ( 某种范围上讲这是特殊处理 ) ,这种特性称之为长时间事务 (LRT) 。
业务流程也可能需要对中心事件做出反映。这样的事件可能是消息事件或者警告事件。通过在端口类型上的调用操作消息事件由引入消息触发。警告事件是时间相关的,并且在一段持续时间之后或者一个特殊的时间触发。 BPEL 对业务流程中的事务管理提供了很好的支持。
这样就有并发活动。在 BPEL 中并发活动使用活动来模拟。在标签内聚集嵌套的活动非常直观,也对表示那些并不太复杂的并发场景非常有帮助。为了表达更复杂的场景,提供在活动之间表达同步依赖的能力。换句话说,我们可以具体指定哪个活动能够开始,什么时候开始 ( 依赖其他的活动 ) 并且可以定义复杂的依赖。举例来说,我们常常指定一个特定的活动或几个活动必须在其他一个或几个活动结束之后才能开始。
与 web services 的无状态模式相比业务流程模式需要使用一个有状态的模式。当一个客户端开始一个业务流程,一个新的实例将会创建。这个实例在业务流程的生命周期中存在。发送给业务流程的消息 ( 使用在端口类型和通信端口上的操作 ) 需要被转送到正确的业务流程实例。 BPEL 提供使用特定业务数据来保存指向特定业务流程实例的机制。这种功能称为相关性 (correlation) 。
我们可以继续讨论,不过很明显 BPEL 已设计用来满足定义业务流程的需要。很明显, BPEL 作为一种编程语言或是一个平台来说都不能取代 Java 。事实上, Java 平台是运行 BPEL 流程的一个选择。
BPEL 服务器和开发工具
为了执行 BPEL 流程我们需要一个音乐演奏式的服务器。这样的服务器为可执行的 BPEL 业务流程提供一个运行的环境。 BPEL 与 web services 紧密相关,也和支持 web service 开发的现代软件平台紧密相关,特别是 J2EE 和 .Net 平台。
BPEL 服务器可以使用 J2EE 或者 .Net 应用服务器的环境,这样他们可以使用应用服务器提供的服务,比如安全,事务,可伸缩性,和数据库的集成, EJB 组件服务,如 JMS 的消息服务等等。
BPEL 服务器在 J2EE 和 .Net 平台上都已存在。在 J2EE 平台下我们至少可以在以下中选择:
Oracle BPEL Process Manager (http://www.oracle.com/technology/products/ias/bpel/index.html)
IBM WebSphere Business Integration Server Foundation (http://www.ibm.com/software/integration/wbisf)
IBM alphaWorks BPWS4J (http://www.alphaworks.ibm.com/tech/bpws4j)
OpenStorm Service Orchestrator (http://www.openstorm.com)
Vergil VCAB Server (http://www.vergiltech.com/products_VCAB.php)
Active Endpoints ActiveWebflow Server (http://www.active-endpoints.com/products/index.html)
ActiveBPEL engine (http://www.activebpel.org/)
Fivesight Process eXecution Engine (http://www.fivesight.com/pxe.shtml)
基于 .Net 平台的 BPEL 服务器包括:
Microsoft BizTalk 2004 (http://www.microsoft.com/biztalk/)
OpenStorm Service Orchestrator (http://www.openstorm.com)
OpenStorm 提供包括 J2EE 和 .NET 平台上的解决方案。除了 BPEL 音乐演奏式服务器之外还有一些可用的 BPEL 设计工具。这些工具支持对 BPEL 流程的图形化开发并通常和服务器集成在一起:
Oracle BPEL Designer
IBM WebSphere Studio Application Developer, Integration Edition
IBM BPWS4J Editor
Vergil VCAB Composer
Active Endpoints ActiveWebflow Designer
当 Vergil VCAB Composer 在 .NET 平台上建立时, Oracle, IBM 和 Active Endpoints 的解决方案则是基于 Java Eclipse 框架。我们可以看到在 Java 平台上更多可用的 BPEL 服务器和设计器。
BPEL+jAVA
我们已经看到 BPEL 是组合 web services 成为业务流程的合适语言。 BPEL 不是一般普适性语言 ( 也不想成为 ) 。因此 BPEL 和 JAVA 相互配合, Java 负责 web services 的编程实现和 web services 与 BPEL 流程的执行平台。
如在规格说明书中提到的, BPEL 是可扩展的。特别是 BPEL 可以扩展至 web services 之外是非常有前景的。这意味着我们可以使用 BPEL 组合不同的资源而不仅仅是 web services 。在 J2EE 平台中,可能包括 EJBs , JMS , RMI , JCA 和其他资源。对于这个问题通常有两种解决方法:
支持 BPEL 和 Java 代码的混合,这就是 BPELJ 的思想
用 WSDL 描述所有的资源 (Java classes,EJBs,JMS 等等 ) ,这是 Web Services 调用框架中的思想
BPELJ 提供在 BPEL 流程定义中包含 java 代码 ( 称之为 JAVA 片断 ) 的可能性。这一方面使我们能够从 BPEL 中直接调用 Java 资源 (BPELJ 支持 Java 合作者链接 ) ,另一方面,它给了 BPELJ 增强的能力,因为使用 java 片断,我们可以执行诸如计算值,构建 XML 文档之类的任务,也可以不用创建 web 服务就执行其他代码。我们也可以使用 BPEL 变量表达 JAVA 代码片段。 IBM 和 BEA 支持 BPELJ ,并且已经发表了 BPELJ 的白皮书。
将 java 代码整合进 BPEL 流程以支持调用 JAVA 资源是非常有用的。但是,在某些情况下这样的处理方式也会带来缺点。对一个 Java 资源的调用不同于对一个 web service 的调用。 web 服务调用框架 (WSIF) 遵循另外一种处理思路:在 BPEL 中使用相同的语法调用资源或服务并使用 WSDL 来描述,即使它是一个不通过 SOAP 协议通信的 Java 资源。 WSIF 也允许我们将这样的服务和实际的实现与协议相映射。
换句话说,我们可以把对抽象服务的描述与基于 SOAP 协议的实现绑定,与 Java 类绑定,与 EJB 绑定或者其它支持的资源,这只需要修改 WSDL 绑定即可。在 BPEL 中没有代码的更改是必须的而支持 BPEL 扩展也是需要的。对这种绑定的支持在由 WSIF 提供的支持者那里是坚定不移的。
WSIF 是最初由 IBM 的 WSTK (Web Services Toolkit) 开发中 alphaWorks 部分发展而来的 Apache 技术。现在如 Oracle BPEL Process Manager 的一些 BPEL 服务器已经支持 WSIF 。
这两种方法, BPELJ 和 WSIF 都适合现实世界的场景并且使得 BPEL 在 EAI 和 B2B 中都非常有用。
结束语
BPEL 是面向过程转向面向服务的一种重要语言。因为 BPEL 具体设计用来定义业务流程,因此对业务流程的很多特殊性有很好的支持,如长时间事务,补偿,事件管理,相关性等等。 BPEL 非常适合和 J2EE 平台一起使用,很多 BPEL 服务器也是建立在 J2EE 之上的。结合 BPEL 和 Java 的 BPELJ 以及 WSIF 的思路使得 BPEL 的可用性越来越好。应该看到正在制定的 JBI(Java Business Integration) 规范将会在 JAVA 平台里给业务集成和 BPEL 一个更好的备有证明文件的位置。