提到工做流不少人就会想到OA,的确OA就是典型的工做流的应用,可是工做流并不只仅局限于OA,工做流应该算是基础框架软件,主要用于流程的重组和优化,它有广阔的应用领域。在java下有不少优秀的开源工做流能够选择好比activit五、jpbm4等,在.net下却几乎找不到使人满意的工做流引擎可用。固然不是说.net下没有开源的只是有些国产开源的但看了代码后就一点兴趣都没有了,且不说代码质量如何,还引入了一大堆的东西,想在项目中应用也是很是困难。鉴于此我仍是决定本身开发一款.NET微型工做流引擎。java
为何叫微型工做流引擎?就是超轻量级,以方便在项目中轻便的使用,好比只有一个类库dll,大小也就几百k到1M左右,不过咱们要先回过头来看看工做流系统,它实在是太大了,它应该包括:
一、工做流引擎
二、工做流设计器
三、工做流管理系统
四、表单设计器node
目前来讲的我只实现了核心引擎,流程定义也只能先在xml中编辑而后读取到引擎中或者直接定义到数据库中,但整个流程是可以正常流转。至于流程设计器、表单设计器、工做流管理系统这个我有精力了再慢慢开发。这里我完成的只是很小的一块,可是是工做流的核心,能够很方便的嵌入到业务系统中应用。web
引擎主要提供了对于工做流定义的解析以及流程流转的支持。工做流定义文件描述了业务的交互逻辑,工做流引擎经过解析工做流定义文件按照业务的交互逻辑进行业务的流转,工做流引擎一般经过参考某种模型来进行设计,经过调度算法来进行流程的流转(流程的启动、终止、挂起、恢复等),经过各类环节调度算法来实现对于环节的流转(环节的合并、分叉、选择、条件性的选择等)。算法
一、从概念开始解释估计你们都会看不下去了。咱们先拿一个简单实例来看看,新建一个项目,引用个人工做流引擎类库(Chitu.Bpm.dll,取名为赤兔)。
在项目启动时配置流程引擎(Global.asax.cs中),以下: sql
//初始化流程引擎 BpmConfiguration .Instance() .Config(@"C:\Configration\BpmConfig.xml") .Start();
在项目中使用时,好比新建流程定义:数据库
//取得工做流上下文 var bpm = new BpmContext() .UseTransaction(true) .SetActor("萧秦"); //新增流程定义 bpm.NewProcessDefinition("请假流程") .SetXmlFile(@"C:\Definition\demo1.xml") .SetCategory("分类1") .SetEffectDate(DateTime.Now) .SetExpireDate(DateTime.Now.AddDays(180)) .SetMemo("memo1") .Create() //建立流程定义,只生成bpm_definition_process表 .Parse() //解析xml .Deploy(); //发布流程
启动流程:express
//启动流程 var process = bpm.NewProcessIntance("请假流程ID", "萧秦(业务ID)"); //建立流程实例 process.SetVariable("流程变量1", "值1"); //设置流程变量 process.Start();
人工任务节点转交下一步:c#
//任务完成 var task = bpm.LoadTaskInstance("任务ID"); task.SetVariable("任务变量2", "xx"); task.Signal(); //触发令牌流转
全部的操做都经过Facade模式集中到BpmContext中,操做简单方便。框架
二、接下来咱们先看看流程定义的XML,如下是我捏造的一个流程,以便把各类节点都放进去了。async
<?xml version="1.0" encoding="UTF-8"?> <process name="样板房装修流程"> <start name="装修申请"> <transition to="装修方案设计" > <action class="Namespace.MyActionHandler"></action> </transition> </start> <task name="装修方案设计"> <transition to="装修方案审核"> <action script="log.Debug('装修方案审核 action test');"></action> </transition> </task> <decision name="装修方案审核"> <transitions> <transition to="装修筹备" condition-expression="variable.pass == true"></transition> <transition to="装修方案设计" condition-expression="variable.pass != true"></transition> </transitions> <events> <action event="enter" class="enterHandlerClass"></action> <action event="leave" class="leaveHandlerClass"></action> </events> <assignments> <assignment owner="{process.starter}"></assignment> </assignments> <variables> <variable type="boolean" name="IsPass" access="read,required"></variable> </variables> </decision> <fork name="装修筹备"> <transition to="装修合同签订"></transition> <transition to="等待装修工人到位"></transition> <transition to="装修材料预算"></transition> </fork> <sign name="装修合同签订" necessary="false" async="true"> <transition to="装修施工"></transition> </sign> <wait name="等待装修工人到位"> <transition to="装修施工"></transition> </wait> <task name="装修材料预算"> <transition to="材料采购子流程"></transition> </task> <subflow name="材料采购子流程"> <transition to="装修施工"></transition> </subflow> <join name="装修施工"> <transition to="施工验收/付款"></transition> </join> <auto name="施工验收/付款"> <transition to="装修完成"></transition> </auto> <end name="装修完成"> </end> <events> <action event="process-start" class="TestStartHandler"></action> <action event="process-end" class="TestEndHandler"></action> </events> <variables> <variable type="string" name="start_id" access="readonly,required"></variable> <variable type="string" name="start_person"></variable> </variables> </process>
定义的根节点为流程(process),流程下为各个任务节点(node),任务节点分为:
start 开始节点
auto 自动节点
task 人工节点
decisioin 决策节点
fork 发散节点
join 聚合节点
sublfow 子流程节点
sign 会签节点
wait 等待节点
end 结束节点
任务节点下能够包括路由(transition)动做(action)及人员分配(assignment)变量定义(variable)
其中action包括几种类型:一、class 二、script 三、sql 四、webservice 五、expression
在script或expression中能够直接访问process.xxx属性或task.xxx属性或variable.xxx简化了动态c#语句的使用。
固然XML定义中还有不少其它的属性定义我这里也没有都列出来,之后用到了再仔细说。
三、关于数据库设计,这里仅仅是流程流转核心所须要的表,表之间都没有拉关系
a、我把它划分为主要的几大模块: 引擎配置、流程定义、实例流转、日志处理、计划任务
引擎配置:配置引擎实例的数据库链接、日志配置、参数设定等。
流程定义:利用xml来描述流程,主要定义任务节点,路由、动做事件、变量、人员分配等
实例流转:根据定义运行流程实例
日志处理:输出日志
任务计划:会启动一个服务,用于处理好比延时启动,任务过时等
b、流转中的关键性类设计包括:
一、流程对象(Process)
二、工做任务(Task)
三、路由(Trasition)
四、令牌(Token)
五、事件总线与动做处理 (EventBus、ActionHandler)
六、人员分配及委托机制(Assignment、Depute)
七、流程回退处理(RollbackService)
八、消息服务(NotifyService)
c、一般引擎控制流程调度流转核心的调度算法主要有FSM以及PetriNet两种,基于调度算法来完成流程的流转:
一、FSM(有限状态机)
FSM 的定义为包含一组状态集(states)、一个起始状态(start state)、一组输入符号集(alphabet)、一个映射输入符号和当前状态到下一状态的转换函数(transition function)的计算模型。当输入符号串,模型随即进入起始状态。它要改变到新的状态,依赖于转换函数。在有限状态机中,会有有许多变量,例如,状态机有不少与动做(actions)转换(Mealy机)或状态(摩尔机)关联的动做,多重起始状态,基于没有输入符号的转换,或者指定符号和状态(非定有限状态机)的多个转换,指派给接收状态(识别者)的一个或多个状态,等等。遵循FSM流程引擎经过状态的切换来完成流程的流转。
二、PetriNet
信息流的一个抽象的、形式的模型。指出一系统的静态和动态性质。PetriNet一般表示成图。遵循PetriNet流程引擎经过令牌来决定流程的流转。
我采用的是第二种PetriNet算法。用Token来表示当前实例运行的位置,也利用token在流程各个点之间的转移来表示流程的推动,以下图所示:
令牌流转逻辑,我把如下类方法都作一个简化省略了路由选择及节点处理细节,好让你们明白令牌的流转:
//令牌Token类中Signal public void Signal() { fromTask.Leave(executeContext); } //任务Task类中的Leave public void Leave(ExecutionContext executionContext) { transition.Take(executionContext); } //路由Transition类中的Take public void Take(ExecutionContext executionContext) { toTask.Enter(executionContext); } //任务Task类中的Enter public void Enter(ExecutionContext executionContext) { Run(executionContext); }
至此令牌成功的从一个节点转移到下一个节点了,令牌的流转是工做流的关键,固然不一样的节点处理是有所不一样的,其中最复杂的当数发散节点及聚合节点了。这里就介绍到这里,再也不给你们详细介绍了。
d、目前我引擎中实现的主要包括如下功能:
一、解释过程定义
二、控制过程实例—建立、激活、挂起、终止等
三、控制流程调度流转
四、自定义动做及事件发布
五、流程变量及工做变量处理
六、任务计划,好比延时启动,任务过时等
七、委托服务,委托代办
八、回退服务,回退到任意节点或召回
九、消息服务,好比认领通知、待办提醒、催办消息…
十、流程任务监控服务
十一、日志处理及历史记录
十二、任务分配与认领
1三、参与者组织模型接口
目前个人这款工做流引擎还在继续完善当中,我总结下它的优缺点: 优势: 一、它是一款超轻量极或者说是微型的工做流引擎,并且绿色无污染,它只有一个dll,大小仅1M左右。 二、它目前支持SQL Server、MySql、Oracle、SQLite、PostgreSql等多种数据库 三、体型上来讲它虽然是微型,但功能上并不算微型,它的设计结合了现代的OA及传统工做流、基本上能够实现咱们大多数的功能须要。 四、它实际上是面向开发者设计的,从上面初始印象中的实例代码中你们能够看到,它的接口是很集中、精简、友好的,让开发者容易理解并且使用起来更方便简单。因此它更适合嵌入到项目中开发。 缺点: 一、它如今没有流程设计器、管理系统、表单设计器等,充其量只能算是一个类库,并非直接拿来就可使用。 二、目前刚刚完成第一个内部版本,并且目前只在咱们内部项目中使用,因此它不够成熟,虽然咱们会持续的改进和完善。 三、缺少成功应用的案例。 对于咱们本身来讲,这些缺点都是咱们须要继续努力的地方,可能还须要大量的时间来完成。目前来讲咱们还不打算开源,等它慢慢稳定成熟后咱们会考虑是否是开源出来。若是你们有好的建议或有哪方面的疑惑我很乐意给你们解答,或者你也在设计开发本身的工做流,咱们能够相互交流下。联系13606021792