简介
OMG SoaML 规范引入了服务架构的概念,是用于对一组参与者如何通过所提供和使用的服务进行交互以完成结果来进行建模的。这是一个相对简单的概念,反映企业长期以来一直在做的事情。但是过去存在各种不同的建模方法,以及由
UML、SoaML、SysML 和 UPDM 所支持的不同建模选项,使面向服务架构(SOA)建模人员感到混乱。
在本文中,您将了解服务架构的概念:如何指定参与者,如何封装他们之间的交互,如何将它们反映为服务协议,以及如何表达他们打算交付的结果。首先,您将了解类和实例建模之间的区别。希望这可以消除由过去建模功能决定的实践所造成的混乱。最后,您将使用这些概念,从两个角度开发服务架构:
一路走下去,您将会了解到在 SoaML 中所谓基于接口与基于契约的服务交互建模方法之间的差异。本文将告诉您为什么这些并不是对同一件事的不同建模方法。相反,它们是不同的建模功能,可以表达更有趣、更复杂的交互。
然后,您将在服务架构中显示参与者之间交互的几种方式中使用这两种不同的服务建模方法。
我们希望,本文将澄清并演示面向简单的建模需求和更复杂情况的各种不同建模选项,并帮助您建立您可以使用的实践指南,使您从您的
SOA 模型中获得最大效益。
类建模与实例建模的比较
在探索不同类型的服务架构之前,确保您已了解建模事物以及事物之间的连接的下列两种不同方法,这是有帮助的:
基于类的建模
关心的是,对事物(该事物属于某个类或根据某个类进行分类)的描述。例如,一个
Person 类描述真实世界的某个事物,它有一个名字,有居住地址,等等。
基于实例的建模
关心的是事物(该事物通常按一个或多个类进行分类)的特定用途。例如,Fred
可以是 Person 的一个实例,他住在 Irving Lane 220 号。Person 类会使用名称描述该类的实例。
在 UML1.0 及更高版本,以及 Business Process Modeling
Notation (BPMN) 2.0 等一些建模语言中,类和实例之间的区别相当有限,甚至没有区别,从而把它留给上下文或用户的需求。例如,在
BPMN 中的池可以代表参与者。但有没有办法区分作为类的 Retail Store 和作为实例的 Walmart。因此,许多建模人员曾使用(并仍在使用)UML
类关系图作为建立这样一个上下文的方法,在该上下文中,在一个特定的关系图中所描绘的类、属性和关联,被视为代表这些类的某种用途,并往往用类关系图的名称来描述。这种方法吸引人的地方在于它的简单性。您只需要创建一个类关系图来显示您感兴趣的内容,并且您不必担心类与实例图的区别,也不必担心内部结构。
但是,这种方法成本较高。它使用图表或视图来做两件事:
然而,这种模型和视图的耦合会引发关于关系图和模型含义的真正问题。例如,在一个关系图上显示的属性、关联、方法、超类等,当它们出现在其他关系图上时,它们是否适用于类?或者,您是否预期工具使用关系图来定义一些语义上下文,并使用这些定义来推理该模型的含义或作为转换的输入?类之间的连接是否意味着这些类的所有实例必须被连接为指定的或仅在特定关系图中的实例?我们不可能知道,因为含义以惯例为基础,而不是以正式的建模技术为基础。没有办法区分两种事物,一种是为了删除不必要的详细信息以帮助沟通而被省略掉的事物,另一种是在某个关系图中有语义含义,而在另一个关系图中没有语义含义的事物。
UML 2 针对类建模和实例建模提供明确支持,以避免这种语义歧义性。类可用于定义特定上下文,其中,内部结构中的务部件明确地建模对程序集内其他类的实例的引用。相同的类可以用于定义一些其他上下文中的其他部件,并且这些用途是完全独立的。这种解耦是重用(在
SOA 中起着重要作用)的基础。
SoaML 使用 UML 2 建模功能来帮助分离不同的问题,并促进服务架构中的重用。它依赖于对不同利益相关者根据适用于所有视图的语义含义对某事物的不同看法的清晰分离。
但在 UML 中,复合结构中的连接器与使用类关系图上的依赖关系线定义类之间的关系的这两种概念仍然存在混淆。SoaML
没有限制依赖关系线的使用,但是,SoaML ServicesArchitecture(如规范中所述 )一般不会使用它们。(稍后在介绍服务架构中参与者之间的连接时将详细介绍这一点。)
创建服务架构
有两种常见的方法可以定义 SoaML ServicesArchitecture:
- 第一种是自上而下的设计,其中定义了服务架构以对探索参与者以及他们的连接方式提供一个上下文,以完成结果。这种方法适用于发现可能需要进行调整或构建的候选服务。
- 第二种方法是自下而上的,其中服务模型已经存在,并有 ServicesArchitecture 被创建为一种在较高层次描述该模型的方法。
虽然这两种方法在 ServicesArchitecture 的创建方式及其使用目的而言有相当大的差异,但内容是相同的。本文通过一个自上而下的示例开发来介绍这两种情况。然后,本文演示如何创建最终结果的自下而上的视图,以探讨不同的显示选项。
通过自上而下的设计方法创建 ServicesArchitecture 时,重要的是要考虑正在解决的问题或您试图完成的结果。这应该提示了一个对潜在用户有意义的
ServicesArchitecture 名称。使用 SoaML 规范中采购订单处理的示例作为您的问题领域,并从要出售给消费者产品的制造商的角度来进入这个问题领域,您可以为制造商定义一个服务架构。
图 1. Manufacturer 架构
添加参与者
接下来,添加参与者。在服务架构中,用部件或角色代表参与者,这是 UML
Collaboration 的一个扩展。这些参与者都参与制造:
订单处理员
负责处理订单
生产
履行订单,可能包括新产品或自定义产品的开发
发货人
将订单从生产中心发货给下订单的客户
开票员
处理订单的发票,并处理所有计费职能
这个架构代表制造的需求方视图,其中所收到的订单会严重影响所生产的产品。其他类型的服务架构可能采用不同的视图(如供应方视图),并可能会涉及一些相同或不同的参与者。
在自上而下的场景中,您可能会或,也可能不会有为这些部件定义类型的参与者类。但这都无所谓,因为你可以很轻松地使用所提供的现有类,稍后再添加部件或角色的类型,或在添加部件时创建参与者类。这是一个工具和工作流的问题,而不是特定于
UML 协作或 SoaML 服务架构的问题。那么,保持简单,并假设参与者类尚未定义,因此,您将在服务架构中把参与者创建没有类型的部件。您对这些部件的命名将提示它们在服务架构中所扮演的角色。
图 2. 添加参与者
现在,在您的整个企业或解决方案架构的上下文中检查服务架构,其中一个检查方法是搜索资产重用库获得参与者类。在定义这些类后,您可以使用它们来设置服务架构中各部件的类型。最好在指定参与者之间的连接之前完成这一步,因为这些类型将决定哪些连接是有效的。当然,在未指定类型的情况下,您可以创建部件之间的连接器,以显示哪些参与者需要交互,但在指定类型之前,您都无法以任何方式对这些连接进行验证。
注:
如果未指定参与者类型,就不可能指定参与者之间的角色绑定,以及代表双方之间协议的服务契约。参与者必须知道这些连接被指定。下一节将介绍这一点。
图 3 显示了更新的服务架构,其中已为参与者指定了参与者类型。请注意,参与者的名称表明了该类所描述的事物,但角色的名称表示那些类在特定上下文中所扮演的角色。
图 3. 设置参与者类型
请注意,现在角色所显示的端口描述了为每个参与者提供和使用的服务(如果它们已被定义)。这使您能够显示服务架构所涉及的实际服务的更多详细信息,谁提供它们,谁使用它们。如果您打开端口的标签,在同一个关系图上还可以显示更多详细信息,您可以查看详细的服务和请求,以及所提供的和所需要的接口。
图 4. 服务详细信息的关系图
如果这过于详细,您可以使用外观属性,为端口标签和类型化元素标签的样式选择更好的格式。根据选择,示例关系图(图
5)将原型显示为装饰,而端口标签只使用名称。
图 5. 隐藏不必要的详细信息
重点是,在模型中拥有全部信息,并不意味着必须始终在每一个关系图上显示一切。建模工具和
UML 表示法为您提供了灵活性,可以只显示利益相关者需要的内容,同时在模型中保留全部信息。
现在,您知道制造的服务架构以及涉及到哪些参与者。但您还不知道参与者如何交互,也不知道服务架构意图提供什么结果。
在扩大模型以捕捉这些信息之前,考虑采用以下不同方法定义服务,指定参与者之间的潜在交互。
定义服务
这是 SoaML 规范中存在混淆的另一个领域。SoaML 试图提供用于定义简单服务和复杂服务的设施。该规范讨论两个不同服务定义方法:
这并不是以不同的方式叙述同样的事情;更准确地说,它们是不同的建模功能,提供更多方式表达不同复杂程度的交互。它们可以在相同的模型中,甚至在相同的服务中一起使用。例如,使用服务接口定义一组相关的服务,然后使用服务契约将它们合并成一个更大的多方服务,这可能会很有用。另一种思考方式是,服务接口
通过在所提供和所需要的接口上指定约束来定义服务。服务契约 通过在一组服务接口上指定约束来定义一个更复杂的服务。
在 UML 中,组件封装某个行为的实施。组件的接口是单独定义的,从而将用户从任意特定实现中分离出来,这使得随着时间的推移而发生的替换和演变不会对客户端造成不必要的影响。
UML 支持不同的方法来定义组件的接口:
- 组件可以实现或使用任意数量的接口,指定它提供的操作和它需要的操作。
- 组件可以实现一个定义了静态和动态接口的规范组件。
- 组件可以提供一些有类型的端口,描述与其他组件交互的封装。
这三种方法支持用于管理组件之间耦合的不同技术。规范组件在规范级而不是实现级上实现组件之间的关联和连接。规范组件是比简单的接口更丰富,它可以指定所提供的和所需要的接口,以及预期的行为或组件的生命周期,所有实现组件都必须遵守这些规范。任何规范组件的实现都是独立的。这通过消除特定组件实现之间的依赖关系,减少了耦合。工厂方法可以用来选择可以满足开发人员需求的实现。
端口通过封装和分离某组件与其他组件之间的交互,为任何组件或规范组件提供进一步解耦。这是
SOA 的基础(通过封装组件之间的规范、实施和交互以管理一致性和耦合)。
在大部分现代编程语言中,组件实现一个或多个接口,以定义规范。UML 2
和 SoaML 又向前迈进了一步,将特定的交互点抽象为可实现特定连接的端口。这样,通过在单独的端口上抽象参与者之间的交互,可以减少在
SOA 中的耦合。修改与一个参与者的交互,或更换另一个参与者,不会对与其他参与者的交互产生任何影响。端口的目的是解耦参与者。SoaML
限制 UML,要求所有参与者之间的交互都通过端口连接完成。
SoaML 认识到,并不是所有服务都是相同的。有一些服务比其他服务更复杂,它们可能同时拥有所提供的和所需要的接口,交互可能需要遵循一定的协议,并且交互可能在较长时期中涉及多方。为了支持这种多样性,SoaML
提供了多种描述服务的方法:
- 用于类型化服务端口的简单 UML 接口
- 用于类型化服务端口的 SoaML ServiceInterface
- SoaML ServiceContract
用于类型化服务端口的简单 UML 接口
该接口通过消费者可以调用的操作和将发送到提供者的接收,来描述消费者和提供者之间简单交互。但是,对于这些操作何时可以或应该被调用,事件的接收何时或以何种顺序发生等,它则不能表达与这些问题有关的任何协议。例如,Scheduling
ServiceInterface 仅仅是一个简单的 UML2 接口
图 6. 简单的服务接口
用于类型化服务端口的 SoaML ServiceInterface
SoaML ServiceInterface 利用描述所提供的和所需要的接口和协议(通过
ServiceInterface 拥有的行为)这个功能扩展简单的界面。例如,InvoicingService
是一个更复杂的服务接口,它需要一个协议。协议规定必须在 initiatePriceCalculation
后调用 computePriceCalculation。
图 7. 带有协议的复杂服务接口
SoaML ServiceContract
该接口通过消费者和提供者在一个特定服务的上下文中所扮演的特定角色的规范在端口上定义了更多约束,角色独立于任何特定消费者或提供者。服务契约对于多方服务非常有用。
图 8 显示 InvoicingServiceContract。
图 8. 服务契约
这些方法之间有一些重叠,如何处理重叠,这是一个样式的问题。至少,每个端口必须有一个类型(至少一个接口)。如果有一个简单协议,可以在
ServiceInterface 中描述它,所有消费者都能轻易地看到 ServiceInterface,并且它定义了提供者的价值主张、功能和承诺。
反过来,消费者可以定义指定其目标、需求和期望的 Request 端口。然后,ServicesArchitecture
通过简单的连接器或 SoaML ServiceChannels 将服务消费者请求端口连接到兼容的服务提供者服务端口。
在更复杂的情况下,对于任何特定的消费者或提供者独立描述得最好的特定服务或请求可能会有更多约束。在多方服务交互中往往就是如此。ServiceContract
在这种情况下很有用。ServiceContract 是 UML Collaboration 的扩展,参与者在参与由服务契约定义的服务时预计将扮演的一组角色,ServiceContract
为指定这些角色之间的交互提供了一个方法。这种协作定义了参与者之间的协议,独立于任何特定的参与者,从而在各参与者之间提供更高程度的解耦。通过将服务架构中的参与者部件绑定到他们在服务合同中所扮演的角色,服务架构可以显示正在使用服务契约的参与者之间的协议和连接。然后,限制这些参与者提供与他们所绑定的角色类型兼容的端口,并且他们在通过该端口进行交互时的行为要以服务契约的规范为根据。端口的类型必须兼容它所绑定的角色,但它并不需要是完全相同的类型。端口的类型可以是简单的
UML 接口,也可以是更复杂的 SoaML ServiceInterface。
因此,在 SoaML 中其实并不是有基于接口和基于合约这两种不同的服务描述方式。更准确地说,有不同的方式通过不同的建模功能来定义服务,以满足不同复杂程度。您可以使用三种方法中的任何一种,对广泛的服务描述需求进行建模:
UML 2 接口可与协议状态机器关联,可以描述服务或请求协议,以便使用在接口中定义的操作和接收。
SoaML ServicesInterface 也可以使用多个部件限制超过两个参与者之间的交互。
SoaML ServiceContract 可以用于对涉及两个角色其中一个角色没有明确指定的服务进行建模。
但在实践中,如本文前面所述,最好的方法是当接口足够时使用简单的接口,当需要协议时使用服务接口,并使用服务契约支持多方交互。
连接参与者
您现在已定义了服务接口和契约,服务架构已经建立,您已经添加了参与者。接下来,您要解决如何连接参与者。
回想一下,SOA 的标志性特性是,各方之间的交互被抽象并封装,以减少和管理服务消费者和提供者之间的耦合和依赖关系。这不仅鼓励和支持服务和服务提供者的重用;也使服务消费者选择在其价值链中所使用哪种服务提供者时拥有灵活性,不会对各提供者产生不必要的影响。服务架构中参与者之间的这些连接,正是
SOA 的基本部件,这能在必须管理的系统中建立了耦合。
此外,回想一下,为了特定的用途,您要在服务架构中连接参与者实例。对于要连接的所有这些参与者实例,您并没有以同样的方式进行约束。不同的架构可能使用相同或不同的参与者类型,或以不同的方式使用服务。这正是支持重用和灵活的业务整合所需要的。
如何连接参与者部件有几种选择,取决于交互的复杂度以及在服务架构中要捕获的详细程度。参与者之间的交互,可以用三种方式显示。
使用 ServiceChannels
如果尚未定义端口,可以用 UML 部件(属性)之间的,否则,也可以使用服务和请求端口之间的。这将是典型的使用简单接口或
ServiceInterfaces 定义的服务。图 9 显示了 Manufacturer 架构中通过服务渠道连接的参与者。整个服务渠道中发生的交互必须与定义连接服务和请求端口的接口和服务接口一致。
请注意,改变提供装运服务的参与者,其影响将独立于 orderHandler
参与者的装运请求端口。与其他参与者的交互被服务和请求端口隔离,并且不会导致在 orderHandler
上的直接依赖关系。
图 9. 用连接器连接参与者
使用 ServiceContract 绑定
这些将参与者限制为他们在 ServiceContract 所扮演的角色,如绑定所指定的。同样,如果参与者的端口已知,绑定也可以是参与者或该参与者的一个端口。图
10 显示开票、生产、装运(协作用途)的服务契约的实例,用角色绑定来规定参与者在服务架构中发挥的作用。这个示例在一个较高的水平显示参与者之间的交互,装运角色除外,装运角色被绑定到发货人参与者的特定服务请求端口。这种隔离正是
SOA 的一个关键部分。
图 10. 用服务契约连接参与者
此关系图与前面的关系图表示同样的事情,但它可以对参与者之间的交互上建模更多的约束。
使用依赖关系线
在 UML 2 中支持这种方法,SoaML 没有使用它来描述服务架构。对于类关系图中所描绘的有代表性实例之间的预期交互的快速的非正式草图,可能是有用的。
如前所述,SoaML 不建议在类级别使用依赖关系线来表示参与者之间的交互,因为这将导致更大的耦合和更少重用。然而,可能在某些情况下,您希望将参与者类的所有实例都限制为以完全相同的方式进行交互。依赖关系线将是表达这种约束的一个适当方式。
使用服务渠道或服务契约,在服务架构中对参与者部件之间的交互进行建模,也是同样的意思。服务契约提供了更强的表达能力,可以很容易地对多方交互进行建模。要么选择样式,要么选择表达能力的需要。
描述预期的结果
服务架构旨在完成的任务可以在其自己的行为中描述。服务架构类似于服务契约。服务契约
指定一组角色(由接口或服务接口定义)如何配合工作,以实现单个服务的现实效果。服务架构 指定一组参与者如何通过一组服务进行交互,以完成某个结果。在这两种情况下,都可以通过一个
UML 2 行为对预期的结果进行建模:交互、活动、状态机,或者不透明的行为(在指定的语言中定义)。对于您的
Manufacturer 架构,预期的现实效果是处理采购订单,即履行订单、装运产品并处理发票。可以使用一个
UML 活动来表达这种业务逻辑。
图 11. 服务架构的业务逻辑
服务架构的业务逻辑是服务架构所拥有的一个活动,以 “带圈的加号” 符号表示。活动分区代表在服务架构中的部件。在每个分区中的行动表明哪个部件负责执行该操作,以及何时执行。该活动模型与
BPMN2.0 Orchestration 非常相似。
该行为的意思是,服务消费者和提供者(服务架构中的部件)之间的交互,如建模交互的服务契约或连接所描述的,必须以一种同服务架构行为一致的方式发生。在第一次创建服务架构时,可以勾勒该行为。接着,可以使用活动中的操作来识别候选服务,然后再通过服务接口或服务契约指定这些服务,并由提供参与者实现这些服务。
查看服务架构
现在,从想了解 Order Processor 参与者现有实现的利益相关者的角度来看这个问题。这样的利益相关者可能需要的是,构造一个服务架构来描述在特定实现中参与者之间的交互。例如,试想一下这样的实现,一个
Manufacturer 参与者将参与者组装起来以实现采购订单的处理。
图 12. 组装参与者
该实现显示,通过服务渠道连接的一些参与者,其行为将鉴于某请求以某种方式执行。您想要做的是,构造服务架构来描述或约束这种交互。要做到这一点,您可以创建一个
ServicesArchitecture,并将参与者类拖放到服务架构,以创建有适当类型的参与者部件。然后,您可以将服务契约拖动到关系图中,以创建这些契约的使用,并将部件绑定到相应的角色。这样,只需使用简单的拖放式技巧,就可以从已经实现的参与者、类、服务契约和服务接口建立起服务架构。然后,建模人员可以调整外观和选项,以显示满足其需求的信息。
创建的服务架构将与您使用自上而下的设计所创建的那个服务架构完全一样。工具可以提供不同的显示选项,以删除不必要的详细信息,让您可以提供同样简单的高层次关系图,您可能已经开始使用该关系图来勾画原始的服务架构设计。
最后,正如您可以通过服务架构中参与者之间的服务契约显示参与者在单个服务中所扮演的角色,您也可以显示在一个实现中的参与者如何遵守服务架构。在这种情况下,您只需将实现中的部件绑定到它们服务架构中所扮演的角色。
图 13. 遵守服务架构的参与者
结束语
本文介绍了 UML 和 SoaML 中很多基础概念,包括一些可能会混淆的概念:
基于类建模和基于实例建模之间的区别、用于描绘代表性实例 的类关系图概念,以及相对的复合结构图
的概念,复合结构图描绘以引用实际实例作为在特定上下文中将事物从其用途分离出来的一种方法
创建服务架构作为一个自上而下的服务发现和设计方法,包括指定服务架构、协作参与者、模型与约束它们之间交互的协议,以及您打算让架构完成的任务
使用 UML Interface、SoaML ServiceInterface、SoaML
ServiceContract 或组合,以不同方式指定从简单到复杂的服务描述
从现有的实现以及服务架构如何约束实现,创建一个服务架构视图
我希望您认为本文有用,并且帮您解释了用于表达类似事情不同建模功能所产生的一些混淆的概念。
在以后的文章中,我将介绍 SoaML 和 BPMN 2.0 之间的相互关系,使用
SoaML 帮助了解 BPMN 2.0 业务流程、对话和编排,以及如何配合使用表示法。 |