本文内容包括:
《快速实现服务集成模型》是本系列文章的第四部分。本文承接前面系列文章的分析和建模的结果,主要进行SOA实施的层面上的探讨,首先介绍SOA项目实施的准备工作,然后介绍在实施过程中怎样利用分析建模的结果定义服务并将服务分配到模块中,根据模块的分析得到服务的集成模型,从中总结出一些有价值的指导原则和实施细则,希望对SOA项目方面的开发测试人员有所帮助。本文假定读者能够使用WID进行基本的SCA开发和相关的操作。
引言
以服务为中心的业务活动管理与监控是最近出现的一种热门的IT技术,它的目的在于帮助企业管理人员实时获悉企业运营状况,了解企业的战略实施进展。
《SOA 快速指南 1 2 3》系列文章是笔者近年来在 SOA 项目实施中的经验结晶。该系列文章结合一个汽车贷款流程, 介绍了在
SOA 的环境下如何基于 IBM 的现有产品构造业务活动管理解决方案,详细阐述了每个实施步骤中使用的 IBM 的方法学、技术和产品。希望通过本文的介绍,能够帮助读者理清业务流程管理所包含的基本概念,并了解构建解决方案所需要的基本步骤。
1. 项目实施的准备工作
在本系列的前面3篇文章中,我们已经了解到,通过业务价值分析和服务建模,经过服务架构的分析和设计,我们能够确定需要实现的服务接口和消息规约,以及服务之间的调用关系。现在我们的任务就是如何实现和构建这样一个以服务为中心的应用系统。
实现服务集成模型是本文的主要内容,我们将讨论如何独立实现相应的集成模块,由架构组在整体层面上把握路线,建立集成模型。本系列文章的第五篇将进一步讨论如何逐步实现服务和持续集成服务。
首先简单分析一下我们的目标,我们的工作此时能得到的输入就是本系列文章的前3篇文章中的输出(服务规约、服务实现决策以及系统架构),我们的目标就是获得相应的输出:一个以服务为中心的应用系统。
我们将会采取如下的基本步骤来实现我们的目标:
1 项目准备:准备相关的软件:硬件环境和组件开发团队。
2 在开发环境中定义服务:使用WID工具定义服务的基本元素。
3 决定服务之间的物理关系和服务集成模型:主要是得到服务集成的顺序和路径。
4 逐步实现服务:使用模拟服务的方法快速实现服务和快速测试。
5 持续集成服务:根据服务模型的顺序持续的集成服务,构建完整的应用系统。
|
SOA
快速指南 1 2 3 本系列是 IBM
中国软件开发实验室 SOA 设计中心近年来在 SOA 项目实施中的经验结晶。
- 项目概述
- 第 1 部分:SOA 采纳步骤和价值分析
- 第 2 部分:服务建模
- 第 3 部分:服务实现及架构设计
- 第 4 部分:快速实现服务集成模型
- 第 5 部分:逐步实现服务和持续集成
- 第 6 部分:以服务为中心的业务活动管理与监控
|
|
在开发过程中会包括迭代的开发和持续测试。
首先我们回顾前文的工作成果,我们确认系统将要提供以下服务:
因此我们将开始实现层面的探讨,我们将讨论服务组件的划分和实现过程,服务的组成和聚合关系。模拟服务的实现和测试,UI和后台系统的准备。
在本文中,我们主要根据既定的系统架构,实现每个服务的基本框架和SCA模块的基本内容,用于验证概念,与客户交流,安排开发计划和进度。在实际的项目中,最主要的通过本文的工作内容,得到项目结构的全景,通过评审、项目组会议和演示等手段,使得全组对整个系统的实现架构和组成,每个组员的工作,系统的开发和部署单元等都要有全面的了解。
1.1 开发环境
目前供选择的支持SCA编程模型和面向服务的体系架构的开发的工具还不是很多。IBM公司于2005年10月发布的WID6.0是目前比较好的能够支持SCA的开发工具。实际上IBM公司提供了整条产品线能够实现基于SOA的应用从建模,开发,部署,监控等一系列阶段的支持,请参见图1。
图1:IBM支持SOA的产品线。
为了更好的说明SOA的生命周期和IBM产品的对应关系,这里我们提供一个简单的产品表格(以最新的WebSphere 6系列版本为例),参见表1:
表1:SOA的生命周期和IBM产品对应关系
1.2 团队环境
本系列文章前三篇探讨的内容都是由SOA项目小组的早期成员(架构组成员和项目负责人,客户代表,业务分析师,现存系统架构师等)一同完成的,从现在开始,项目小组的重心向开发的方向转变,工作开始产生新一轮的迭代,新的成员加入,原有成员或离开从事新的项目,或坚守岗位,成为项目开发的主要骨干。
我们认为,本系列文章的前三篇所探讨的话题,从时间的角度来讲,主要发生在项目的早期,视项目大小,其所用时间可能从10天到数月不等,参与人员可能从4、5人到十数人不等。除了客户人员外,项目组在早期可能只包括业务分析人员,SOA架构师和IT架构师。因此和传统的项目类似,在项目的早期,团队构成以分析人员,设计人员和架构师为主。
当SOA项目进行到实现阶段,架构设计已经比较明确,此时开发人员和测试人员就要加入,原小组成员需要一天到数天的时间进行知识共享,使得新加入的人员对项目背景,所实现系统的功能有明确的认识。然后根据项目情况和个人情况,组建开发小组。此时我们建议架构师转变角色为开发小组的TeamLeader,保证开发和项目设计的持续性。同时我们强调小组之间的交流和信息共享,以保证项目进度的透明性,使得开发人员对SOA的认识保持一致。
在我们的项目实例中,我们项目小组的组成如表2所示。
表2:示例项目中的项目小组组成。
通常项目团队的分组可能面临两种选择:
一种是水平分组:按照应用的水平层次进行分组,如UI相关,流程相关,中介相关,服务实现后台系统等。
一种是垂直分组:按业务功能划分,以业务流程为中心,功能相关的UI,流程,模块,后台系统为一组。
在以服务为中心的SOA项目中,我们推荐将项目以服务为中心分为2个大的Work Stream:
1 服务实现:
包括新的服务和对现有服务的包装,这样实现的服务将作为基本的服务组件分布在服务模块中,等待互相调用和被流程等方式进行编排。
2 服务集成
包括从UI到业务流程,或者SCA之间的装配。
这样考虑主要是因为服务的实现是可以独立的完成(我们强调SOA中的Service是粗粒度的业务服务),而服务的集成主要体现在流程以及服务模块之间的装配,这样的划分对于我们将来的持续集成有着非常重要的意义。
每个Work Stream之中,可能需要按业务或者技术侧重分成若干小组,同时Work Stream之中,根据人员技能的不同,每个开发人员的角色会有侧重。各Work
Stream之间需要保持相应的交流,对于一些重要的技术人员或者领域专家,可以在Work Stream之间实现共享,例如在我们的例子中,有一名BPEL专家主要承担流程编排,并同时为各小组提供相关咨询。
在表3中我们列出SOA项目通常情况下开发人员角色(基于J2EE的SOA项目,以IBM产品为例),供读者参考。
表3:SOA项目开发人员角色和技能列表。
2. 定义服务的基本元素
在相关的准备工作完成以后,我们将逐步开始接触服务的实现,首先我们会定义服务的基本元素,包括服务的消息格式和服务接口的定义,以及服务的分组。
2.1 定义业务对象和服务接口
在前面的系列文章中,我们经过分析已经能够给出服务之间的规约,现在是时候要开始在开发环境中实现这些定义了。
在项目实施中,我们通常基于一些表格形式的规约进行开发,这些表格的定义基本上是以业务人员为主,是侧重于真实的业务数据的定义,可能会和以前的业务系统的实现有差别,但是请不要怀疑,毕竟,SOA系统并不是以前的业务系统的简单重构,而是需要我们从业务(Business)服务的角度,规划和设计企业的IT架构。
这里给出一些示例:表4和表5。
表4:服务消息规约示例
表5: 服务接口规约示例
2.1.1 业务对象
业务对象(Business Object)简称BO,在某种程度上你可以认为BO就是SDO一种特例,关于BO的信息,请参考参考资料《深入了解WPS中的业务对象Business
Object》。
示例中的一个业务对象在WID中的定义如图2下所示。
图2:Address业务对象。
在使用WID实施SOA解决方案时,我们推荐将所有的公用的业务对象和服务接口实现于一个Library项目中,供所有需要的模块引用。对于模块内部的私有业务对象和接口,则由模块自己管理。
BO之间的关系可能有如下几种,我们这里简单讨论处理这些关系的时候需要注意的要点:
1 引用
在WID中,虽然在业务集成视图提供了可视化的编辑BO的方式,但你仍然会不时的打开BO对应的XSD定义文件,进行一些手工的操作。
例如,如果你在业务对象A中引用业务对象B,后来又删除了该引用,你仍然需要手工删除业务对象A对应的XSD的import。在SOA迭代的开发过程中,BO之间的关系会经常的发生变化,开发人员必须保证开发工具的视图和定义BO的XSD之间的一致。
2 继承
请注意WID支持BO之间的继承关系,其实现是通过XSD的extension来实现的,WSDL中的消息也是通过XSD来定义的,因此也支持继承。在一个复杂的系统中,业务对象不可能都是一个独立的存在,因此在定义BO的时候,你可能需要考虑继承。并且,我们更关注模块之间共享的BO,这些BO作为消息线索,将串联起主要的业务流程,具有非常明显的业务含义。
例如:我们可能考虑一个抽象的汽车业务对象,派生出客车,货车等不同的业务对象,其对应的贷款规则可能会有变化,通过在流程中组件之间使用抽象的汽车类型,而某些组件内部使用具体类型,我们可以灵活处理,并且类型发生变化时并不影响主要的业务流程。
3 映射
在更为复杂的情况下,WID 支持BO之间的Mapping和Transformer ,从而支持接口之间的Mapping,当然,你也可以使用Mediation模块里面的XSLTTransform来实现消息的转换。
例如保险系统的查询接口,需要使用保险人的姓名,地区,和身份证证件号作为输入,我们可以定义一个保险人查询条件业务对象,使用贷款申请人到保险人的映射来自动完成转换。
实际项目中,在使用WID工具定义业务对象同时,应当尽量将所有的变更记录在案,并和设计文档保持同步。你可以采用自动化的方法,将注释保留在代码中,使用工具生成文档,这样自动保证设计文档和实现的同步。对于定义BO的注释,我们推荐在属性页的注释面板中添加适当的注释,对于在系统间流动的BO,会被不同的开发人员引用,适当的注释可以大量减少你的口舌。对于业务对象中属性,需要考虑到是不是数组,以及是不是必需等问题,我们应该合理的使用这些定义,可以在早期测试的时候发现很多问题。在项目实现过程中,一个微小属性的变化可能带来一系列的问题,因为BO中的属性是强类型的,并且通常会和WSDL接口和Java代码产生很紧密的关联,所以我们应当尽量的事先考虑周全。
2.1.2 服务接口
服务接口的定义在目前的WID中实际上支持两种定义方式,WSDL和Java接口,但一般情况下,模块之间的接口我们使用WSDL,因为WSDL扩展性和通用性都比较好。而模块内部,我们可能使用WSDL,也可能使用Java。如果你的一个Java服务组件不得不引用一个无状态的SessionBean,你就不得不使用该SessioBean的接口来定义这个组件的接口。在使用WSDL接口定义的时候,尽量不要过早的在Process中绑定接口,因为一旦接口的参数的数据组织格式发生变化,Process的调用接口和分配变量部分会发生很大的变化。
如果你希望暴露的接口和你的组件接口不尽相同,你可以使用接口映射,接口之间的映射就需要用到业务对象的映射,而且也可以使用Mediation来做,实际上完成的功能基本上是一样的。
在WID中定义的一个接口示例如图3所示。
图3:WID定义的服务接口示例。
2.1.3 业务对象的映射
SOA采用分层的方法来隔离关注,利用分层可以提高开发和运行时的灵活性,但是层次之间以及层次的对象之间,经常会需要互相映射,这是SOA项目实践中非常常见的一个问题,在定义业务对象的时候,同样需要考虑这样的问题。
SDO的目的是统一数据的格式,然而在遗留系统中难免会有不同的数据源(数据库, LDAP等)虽然SDO提供了访问不同数据源的方式,但是你仍然不能避免SDO和Java对象之间的转化。通常情况下,如果被集成的后台系统是EJB,我们可以使用Web
Service来包装EJB,然后在SCA模块中导入该Web Service 可以实现自动调用,在导入WSDL的同时,WSDL中定义的消息会自动转化为BO的XML
Schema定义。此时我们就可以通过使用Mapping或者XSLT Transformer来实现BO之间的映射,从而隐式的实现BO到Java的映射。如果你的Java对象的定义不含弱类型对象,或者不含特定的业务逻辑,只是简单的映射,你可以使用JAXB或者XMLBeans轻松的通过配置实现Java对象到XML的映射,通过XML快速生成SDO。
有2种情况你将不得不亲自面对Java对象和BO之间的互相映射(转化):
1 在特定情况下,因为效率,事务等的需要,不得不在SCA中直接集成EJB,并且你无法使用WSDL轻易的实现映射,尤其是当数据种隐含若类型对象或者隐含特定的业务逻辑。对于常见的J2EE系统,我们会遇见诸如Vector,List,HashMap这样的参数类型,对于这些弱类型的Java对象,虽然WSDL提供了Any
类型,但是一般不太容易交互,所以对于这种情况,你不得不需要使用良定义的Java对象来包装参数,或者将包装后的方法暴露成Web Service,或者直接手工实现Java和SDO的转化。
2 对于UI的重用性,有时候也要涉及BO和Java对象之间的转化。
对于这些情况,我们推荐你使用自己编写的TransformerFactory来生成每个对象和SDO的转化类。我们实现的TransformerFactory实际上是一个Java代码生成器。
值得注意的是,在生成Transformer的同时,我们可以捎带生成测试数据生成器,使用该生成器,你可以在项目的早期生成满足需要的测试数据,以方便单元测试,集成测试,实现自动化的测试。
在我们的例子中,银行内部的房贷系统就是这样一个后台系统,它暴露出EJB的接口,并且设计上采用Command模式,其中包含大量的弱类型参数以保证扩展性,因此我们无法使用WSDL映射来实现自动调用,不得不采用Java代码手工转化。我们在生成转化类的同时也生成测试数据生成类,这也是我们使用TransformerFactory捎带带来的一个优点。
3. 按不同类型的服务划分服务模块
根据本系列前面的分析,我们已经定义了将实现的服务和接口,但是如何下手开始做服务的编码呢?在SOA的角度,应用程序无非是服务的装配形式,但是,如何组织这些服务呢?SCA
的组件天然的有2种组装模式,一种是模块组装,一种是系统组装,所谓模块组装,就是SCA定义了一种SCA的模块,模块内部会有一个或多个SCA的服务组件通过流程,调用,等方式组成一组功能的集合,该功能的集合(模块)具有显著的业务层面上的价值和意义,所谓系统组装主要就是BPEL,SCA调用等方式,将不同的模块组织,以完成业务流程和业务功能。
WID 为我们提供了很好的SCA开发环境,在WID的环境中进行SOA的开发一般涉及到 SCA模块,Mediation模块,Library等模块。而一个SCA或Mediation模块就会对应多个WID的Project(一个基本的项目,一个Ear项目,一个EJB项目,还有EJB客户端和Web项目等),如果每个服务对应一个模块,就会产生太多的部署单元,系统给人的感觉整体上会杂乱无章,因此我们推荐使用以下地方做法来给服务归类,使用不同的模块来组织这些服务。
1首先将所有的服务归为大类,对于每一类中的多个服务,按照流程相关,中介相关,现有系统相关,新建服务相关,其他相关等模式进行组织。
2 在这个基础上在按功能和业务逻辑上的相关性进行组合,还要考虑部署,开发等的问题,最终均衡各方面的决策,实现一个比较中肯的分类,要以有利于开发和部署为原则,还要和集成的步骤和层次相吻合。
对于每个服务 ,我们可能会使用一些简单的表格来分析,参见表6。
表6:服务分类分析表示例。
对于我们的实际例子,我们最终建立如下的几个SCA模块:
1 购车贷款审批流程模块
这个模块完全是一个流程模块,它实现贷款的流程,调用其他的SCA服务或者Java服务组件来完成功能。其中包括一个子流程:信用评估流程模块。
2 信用评估流程模块
将信用评估子流程独立出来是希望将来灵活的变化或者根据地区进行定制的时候使得影响面尽量的小。
3 中介模块
我们抽象出一个中介模块,暴露出后台系统的服务接口,对于不同的客户请求,可能需要路由到不同的后台系统进行不同形式的业务操作,该模块实现了一个中介组件。因为后台系统基于CICS,我们使用MQ
CICS Adapter实现调用的服务组件。
4 贷款系统包装
对于无法直接集成的现有系统,需要单独实现SCA模块,这样便于测试,模拟,也便于集成时隔离和发现问题,同样有利于后台系统地方变更和迁移。视功能情况的分配可能需要分配多个这样的模块。因此我们有一个对贷款系统的包装模块和一个外部保险担保系统的包装模块。
5 保险担保系统包装
保险担保系统包装模块主要实现了对保险担保系统的包装,提供了担保信息查询的服务。
6 汽车价格查询模块
汽车价格查询模块是一个新建服务模块。新建服务的模块主要是针对我们服务建模的时候新发现的服务而言的。对于新的汽车报价查询模块,银行希望自己实现一个简单的数据库查询系统,从某服务提供商处获取数据,每周更新一次。
通过对模块组成和服务调用的分析,我们可以清晰了解到从服务的角度看,系统将要实现的物理结构。此时,关于各个模块的接口,实现方式,逻辑功能,以及一些规约等都要归档,作为下一步开发的基础。
根据以上的分析,我们会得出表7,将服务映射到SCA模块中实现。
表7:服务与模块映射关系。
该结果将作为进一步分析的依据,成为服务集成模型的重要元素。
4. 实现服务集成模型
SCA作为SOA的编程模型,可以给我们带来显著的价值,易于集成,实现高灵活性和高开发效率。到目前为止,我们完成了服务和消息的定义,我们将独立的实现服务模块,UI,和后台系统,所有的这一切都是为了集成,集成为我们最终的应用程序。我们的目标就是要以服务为中心,持续集成。
首先让我们关注服务集成的模型,我们所谓的服务集成的模型主要只服务之间关系建立的计划安排和实现步骤。
为什么需要一个服务集成模型?主要有以下两点的考虑:
1 降低风险
2 最大限度利用资源
使用自动化的测试和基于模拟服务的持续集成将是我们实现目标的主要手段。
请注意,我们设计的示例场景经过简化,结构已经比较简单。我们可以假想将示例放在一个更大范围的应用中来看,该应用集成了网上购车,汽车贷款申请,新车手续办理和车险办理的一条龙服务,极大的方便了用户。在这样一种环境下构建服务的集成模型,持续的进行服务集成将变得更为重要。控制好模块之间的关联,制定合理的集成模型可以有效的控制项目的风险。
4.1 模块内部的集成
一个SCA模块将一些相关的服务按一定的关系进行组装,这些关系我们可以分为:顺序,循环,调用,路由等。模块内部的集成也就是模块内的服务组件之间的集成,从Export直到Import之间的路线的完成,实际上也就是服务调用和服务之间的关系的确立,参见图4。在模块内部的服务进行实现的同时,或者还没有进行实现的时候,就应该开始模块内部的集成。尽早集成,可以在没有功能的情况下用模拟服务实现集成,以获得一个模块内部运行路线的全局观念。在开发的过程中不断的迭代,来实现真实的服务替代模拟服务,对于项目的正常推进是非常重要的。
图4:SCA模块内部的集成示意图。
我们建议如果模块不是足够复杂,模块的实现可以作为一个原子的活动,不用区分服务和模块内部的集成,但是如果模块的规模比较大,对于模块内部的服务实现上还是要有一些考虑。
一般来说我们总是会优先实现简单的服务,对于功能复杂的服务,我们会使用门面或者代理的设计模式,将复杂的业务逻辑分解为独立的实现,在简单服务中包装或者代理这些服务,这样也有利于随时修改调用代码或者硬编码实现模拟服务以供测试使用。
请注意在模块内部的集成时,你不一定需要为模块暴露出接口,也不一定要对任何import进行绑定,因为随着全局观念的清晰化和你对项目认识的深入,很多预先定义的接口形式和绑定方式会发生变化。虽然WID的开发工具使得我们对于项目开发过程中的变化的可以快速响应,无需付出巨大代价,但是我们仍然需要尽可能的将变更带来的风险降到最低。
4.2 模块之间的集成
集成(或组装)是SCA中非常重要的概念,你可以想象如果我们的应用程序是一辆汽车,我们的服务就是汽车零件,服务模块这是汽车中的大型部件,最终,我们需要通过组装来实现我们的SOA应用,并且由于组件之间的良定义的接口,我们的组件都是可以替换的。在
SCA的编程模型下,模块之间的集成主要依赖于SCA调用和BPEL。参见图5。
图5:模块之间的集成示意图。
在模块内的集成进行的同时,项目领导小组则开始进行服务模块之间的集成模型的定义。在我们的实例中,我们增加了2组UI模块,供2种场合的使用(个人上网,业务大厅办理)。
在WID提供的SOA开发模式下,我们认为一个SOA应用会主要由以下一些部分构成:UI、业务流程模块、SCA模块和后台系统。
不同的部分会含有多个模块,模块之间的集成,在我们的例子中,我们可以分为两个层次 :
1 垂直层次:
UI->服务组合->服务实现->后台系统:主要可能分为 与UI的集成,与流程的集成,与现有系统的集成。由于工作量的不均衡,其完成的时间和集成发生的时间点不可能一致。
2 水平层次:
同一类型的模块(如果我们把相关的UI也按模块的相关性分组),之间的进度也不是一致的。
因此,我们会有如下的集成关系分析表:
其中:UI1指大厅用户界面,UI2指网络用户; L1,核心系统;L2,贷款系统;L3,保险系统。
对改表格的横向和纵向的分析将表明我们的模块之间的关系和集成度。
为了保证团队工作量的一致,同时为了降低最终集成的风险,最优化资源,达到最大的效率,都需要我们持续的集成。我们仍然从一个以流程为中心的开发小组为例,首先要考虑模块之间的交叉依赖性,被调用的越多的模块要尽早集成,然后考虑越先完成的模块要越先集成。对于有的模块可能会被多个模块调用,因此有重用交叉的地方优先实现。对于决定系统架构的关键路径上的组件,同样考虑要优先实现,优先集成。
经过各种方面的考虑,我们最终会得出组件的实现顺序和集成顺序,均衡的安排工作量。对于集成的服务模块,首先我们就有实现模块所需时间的考虑,对于模块之间的每个集成都要分析其实现方式,工作量,技术风险等,最终会为每个业务流程得出一个按时间排列的实现和集成任务列表。
根据以上的工作和分析,开发组进本定义了系统的体系结构和一些基础的服务元素,并定义了完整的集成模型,和均衡的计划。下面就需要开发人员根据时间安排,按计划的实现服务,持续的集成服务。至于如何实现持续的集成,我们需要单独实现各服务组件和全面的单元测试,在下一篇文章中,我们将详细探讨。
|