大牛的杰做,赞一个html
转自:NetBPM工做流的架构设计及实现浅析web
读前的话:因为本文涉及内容颇多,如有地方读来不很明白,建议先跳过,总体上有个认识后,再回过头来理解。做者认识有限,如有错误,欢迎斧正:)原文地址: NetBPM工做流的架构设计及实现浅析(转载请保留)数据库
NetBPM由一系列的组件构成,每个组件都实现一个核心接口(采用Facade Pattern)。不一样组件各自负责的核心功能根据WfMC规范而来。
NetBPM接口图:apache
下面咱们逐步介绍NetBPM的各个组件,下面是NetBpm组件结构图:编程
该组件实现核心接口IDefinitionSessionLocal,用来解析、加载流程定义压缩包,并将其保存到数据库中。此外,它还提供获取某个流程定义,获取全部有效流程定义列表等和流程定义相关的方法。架构
该组件实现了核心接口IExecutionSessionLocal,它是NetBPM引擎推进核心,如前面如述,它主要实现2个方法:开始一个流程实例(Start ProcessInstance)和执行一个活动(Perform Activity)。另外,它还提供获取用户任务列表,取消流程实例等辅助流程运转的方法。框架
该组件实现接口IOrganisationSessionLocal,它把全部的组织架构信息都汇集在一块儿,包括Users、Groups和Memberships。运转组件在为activitie-state指定执行者时,须要有关user和group的信息。这些信息将以只读模式由组织架构组件向运转组件提供。下面是NetBPM默认的组织架构组织数据模型。在此基础上,咱们能够很方便的实现自定义的适合实际项目需求的组织架构组件,以和咱们的用户数据库或者是LDAP系统相关联。ide
NOTE:NetBPM源码中实现的只是一个简单的组织架构模型,但它提供了一种思考方向,咱们能够很方便在此基础上进行扩展来实现知足切实需求的自定义组织架构组件:)工具
该组件实现接口ILogSessionLocal,用来记录工做流引擎的操做痕迹,象属性值的更新(如用户提交的表单被上级打回从新填写,那么就会出现屡次表单数据,这就是一种属性更新),委托类的调用状况等都会被记录下来保存到数据库中。单元测试
该组件实现接口ISchedulerSessionLocal,在现实的业务流程中,咱们常常会遇到须要定时触发某个任务的需求,任务调度组件正是做用于此。引擎或者是第三方把须要在某个时刻执行的任务信息(包括任务执行环境、执行时间等)封装成Job保存到数据库中。任务调度组件将按照指定的时间间隔不停的扫描任务表,根据执行时间对比来执行定时到了的Job。
该组件用来对流程定义,流程实例执行状况等进行监控。(源码待完善)下面是NetBpm核心项目在Visual 该组件用来对流程定义,流程实例执行状况等进行监控。(源码待完善)
下面是NetBPM核心项目在Visual Studio解决方案中的源码结构图,全部组件都包含在Workflow文件夹下,每个文件夹分别对应实现了一个核心组件。
flow不知道翻译为何好,在JBPM中叫作Token,翻译为令牌,这里咱们就叫作flow吧。它表明activity-states(活动节点,见nPdl)的一个“thread of execution”,至关因而一次流程实例执行过程当中在流程定义模板中的令牌(还真难描述清楚,看下面一块儿理解:))。前面说了,一个流程实例表明一个流程定义的一次执行。以下图所示,流程实例的状态能够当作是一颗flows树。
当开始一个流程实例后,在start-state(开始节点,见nPdl,start-state实际上能够看作是一种特殊的activity-state)引擎将自动产生一个名为root的flow。flow中包含了该流程实例的相关信息,如属性值、流程定义信息、flow所在activity-state的执行者等。root flow在遇到fork(分散节点,见nPdl)以前,将更新其带有的实时信息(如执行者、属性值等),这些实时信息随着流程的运转而变化。遇到fork后,根据ForkHandler委托类,root flow将分散成若干(>1个)forked flow(咱们能够把root flow称为这些forked flow的父flow)。如果分散为多个,则此时forked flow将并行运行,父flow则暂时退隐,只至到join(汇聚节点,见nPdl)汇聚,引擎将根据join定义的JoinHandler委托类来肯定激活父flow的机制。
NOTE:关于fork和join机制,请参考nPdl fork、join小节一块儿理解。
attribute用来表示流程实例中的变量。一个attribute-instance(属性实例,也就是属性值)表明一次流程实例执行过程当中对应属性的实例。属性通常有几种,一种是activity-state(包括start-state)须要用户或者第三方来填写(更新)的属性(通常对应用户Web界面表单上要填写的值),一种是角色对应的属性,还有一些用做标识属性(用来存储某些信息以方便后面的节点运用这些信息处理逻辑判断)。
由于图片太大,关于继承IHandlerContext的接口关系图查看点击这里
ExecutionContext(ExecutionContextImpl类型的对象,咱们暂且翻译为运行时上下文环境:)) 包含了引擎在运行时和流程实例相关的全部有用信息(上文中提到的flowcontext就是一种ExecutionContext),它在委托类(包括流程定义压缩包中程序集中定义的委托类)和流程引擎之间创建起了相互联系的渠道,这是很是关键的。如上面ExectutionContext 类图所示,ExecutionContextImpl实现了下面这些接口:IAssignmentContext、IDecisionContext、IForkContext、IActionContext、IJoinContext、IProcessInvocationContext、ITaskContext,这些接口都是为匹配特定的委托类而设计,它们规范了一种特定的上下文环境,如IActionContext匹配action类型委托类,IDecisionContext匹配DecisionHandler类型委托类等,而ExectutionContext是全部这些特殊的运行时上下文环境的一个综合。当引擎在运转组件把ExectutionContext做为参数传送到具体类型的委托类时(关键:这就是委托类和流程引擎创建联系的方式),ExecutionContext对象将“拆箱”成为特殊的Context,如:把ExecutionContext对象传给action类型的委托类Run()方法时,ExecutionContext对象将拆箱为ActionContext对象以限制其可以调用的方法。
如“继承自IHandlerContext的接口”图中所示,这些接口都继承了同一个接口IHandlerContext。IHandlerContext是一个规范了最基本的委托类处理上下文环境的接口,实现该接口的继承几口也就都要实现IHandlerContext中定义的方法,固然每一种继承它的特定接口又均可以具备其特定的方法。咱们先看公共接口IHanlderContext类图:如上IHandlerContext接口图所示,这些接口都继承了同一个接口IHandlerContext。IHandlerContext是一个规范了最基本的委托类处理上下文环境的接口,实现该接口继承接口的类也就都实现了IHandlerContext中定义的方法。固然,每一种继承它的特定接口又均可以具备其特定的方法。咱们先看公共接口IHanlderContext类图:
大多数的方法,咱们从方法名称就能够看出其具体做用了,这里重点介绍下GetAttribute()方法和GetConfiguration()方法,这是咱们在写委托类实现时,要常常用到的2个方法。GetAttribute()用来获取流程实例中的属性值,包括流程前面处理者产生的属性值(如用户填写表单的值)和前面处理引擎事件中设置的表示属性值(注:IActionHandler具备SetAttribute()方法,该方法常常用来标识属性值,供后面程序逻辑用)等。而GetConfiguration()用来获取流程定义中设置的parameter(参数,请nPdlparameter小节)。
下面再来看几种典型的特定上下文环境接口:
在前面咱们一直提到委托类,那么委托类究竟是什么呢?这里委托的概念指的不是.NET Framework中delegate,这里能够理解它为“委托、代为处理”这样的概念就好。
NetBPM被设计成通用的流程处理引擎,NetBPM核心执行引擎只负责处理最基本的业务流程逻辑,全部不定的逻辑都被委托给一系列的接口,这些接口称做Delegation Interfaces(委托接口),而实现这些接口的类就是委托类。流程定义约定在什么场合使用什么委托类型,引擎和委托类如何关联也在流程定义中完成。
为了达到最大的可扩展性,流程开发者在流程定义时能够选择下面任意一种委托类实现方式:
正是方式2这种形式给NetBPM带来了极大的灵活性,把只适合于某个特定流程的的程序逻辑(这些每每占了大多数)以.NET程序集的形式定义在流程定义压缩包中,NetBpm经过流程定义组件将其解析并保存至数据库。当引擎运转流程须要调用委托类时,引擎利用反射技术实例化出委托类对象,而后利用上文介绍的运行时上下时环境(ExecutionContext)创建起委托类和引擎之间的交互渠道,这真是一个使人兴奋的设计:)
下面是NetBpm中的委托类型(建议和ExecutionContext一节一块儿理解):
................///////////////////////////.............是否要添加委托类的例子
包含在一个流程定义压缩包中的信息叫作流程定义。NetBpm中,流程是由字段name来区分的,也就是说引擎根据流程的name来判断两个流程是否相等。在流程定义包中不能指定版本,当一个流程定义被引擎加载后,NetBpm将检查是否有该流程定义的旧版本。若是有,NetBpm将自动设置该新加载进来的流程版本为全部存在的旧版本流程定义中最高版本数目基础上加1。
当调用运转组件获取流程定义列表方法时,只能获取到每一个流程的最高版本流程定义。这样作保证了用户老是从最新版本的流程定义开始一个流程实例。当新的流程版本加载到NetBpm时,全部正在运行的旧版本的流程实例将保持在原来流程定义方式下运行。
关于版本的另一个方面是委托类。不一样版本流程定义的委托类不是共享的,也就是说每一个流程在执行时只会“看到”它本身流程定义的委托类。
NetBpm做为一个集成平台,当流程运行时,确定会依赖公司不少其余的IT资源,一旦这些依赖致使流程执行时出现错误,NetBpm提供了3种解决机制:
执行回滚机制中,流程实例将会被回滚到执行activity以前的状态。若是是对NetBpm 调用Eecution Interface时发生流程错误,全部的流过的transition(边)都会执行回滚。
关于流程定义的详细状况,参见nPdl。
NetBpm中用到的框架、组件、工具比较多,它们大都是优秀的开源项目。如Castle,NHibernate,Log4Net, NVelocity,NUnit,NAnt等,不要被这些框架吓倒,实际上,它们仅仅只是“框架”而已:)
NetBpm使用了Castle框架,主要用它来实现IOC(控制反转或者说依赖注入),以依赖注入的方式加载核心组件,如DBClassLoader,流程定义组件,运行组件,日志组件,组织架构组件,任务调度组件等。在Web程序启动的时候,根据配置文件,全部的核心组件都将注册到Caslte IOC容器中,之后当须要使用某个组件的时候,只需利用系统提供的ServiceLocator(服务加载工具类)从容器中获取实例便可。另外,在任务调度组件中也有用到Castle的Startable Facility(注:你们把facility理解为注入性质的,对Castle IOC内核容器的功能扩充组件。Castle自己自带实现了一些faciltiy,开发者也能够自定义facility),该facitlity主要用来自动运行程序(这里用来自动间隔扫描任务表,进行任务调度)。
Castle是.NET平台下一个功能强大的优秀开源框架,关于Castle的更多信息,请看Castle官方网站。另外TerryLee的博客中关于Castle的中文资源也很丰富。
NetBpm中NHibernate组件是做为Castle的一个facility存在的,它用来实现NetBpm数据持久层, 并方便的实现了事务支持。关于NHibernate的更多信息,请看NHibernate官方网站,关于NHibernate做为Castle的facility相关请看这里。
你们在Demo演示体验的时候,必定很奇怪,没有看到熟悉的.aspx页面,而是.rails页面,为何呢?答案就是NetBPM的Web层采用的是MonoRail框架,而不是咱们熟悉ASP.NET框架。MonoRail是Caslte框架下针对web层编程的一个子框架,它从Ruby Rails获取灵感而来,采用架构清晰分工明确的MVC模式。NetBPM采用的使用NVelocity做为页面解析引擎的MonoRail,它只是对NetBPM核心API的一个Web界面演示示例,用来告诉咱们该怎样从Web层调用NetBpm API。因此,虽然MonoRail有其独到之处,可是在其被普及并有好用工具支持以前,咱们只需简单了解下它的运行机制,用以熟悉web层如何利用NetBpm API,不须要了解它太多。用咱们熟悉的ASP.NET实现Web部分显然是更好的选择:)。关于MonoRail的更多信息,请看这里。
log4net你们必定不陌生了,NetBpm使用它来记录系统日志,关于log4net的更多信息,请看Log4Net官方网站,网上中文资源也很丰富.
单元测试工具NUnit一直是你们用来单元测试的利器。 NetBPM源码中已经建有几个测试工程。关于NUnit的更多信息,请看NUnit官方网站。
注:移植到.NET Framework 2.0下,可能要更改其版本。
NetBPM的设计无疑是巧妙的,可是现阶段的它显然还不是一个完美的工做流引擎,缺少如JBOSS这样的强大后盾做支持,中途又赶上强敌WF,NetBPM远没有其兄弟JBPM风光,更新没有它快(JBPM已经出3.0版本了),获取的支持也少量多, 可是.NET平台下能有这样一个优秀的开源工做流项目是十分难得的,若是您正在WF中苦苦挣扎,也许,开源的NetBPM将带给您一个惊喜:)
待写:NetBPM工做流nPdl详解,一个NetBPM现实生活中请假审批示例