上一篇文章我们讲了《》主要对流程编排框架产生的背景,并做了需求分析,这其中包含功能性需求和非功能性需求,算是在正式开始设计之前做一个铺垫。
前面提到,项目实战分为分析、设计、实现、测试几个部分讲解,其中分析环节跟面向对象分析很相似,都是做需求梳理。但是在时间项目中设计和实现就不是这么一回事了这里的“设计”指的是系统设计,主要是划分模块,对模块进行设计。
我们主要分为模型定义、流程加载、流程解析、集成使用这四个模块,来说明编排框架的设计思路,今天讲解的重点是,如何通过合理的设计,实现一个易用,易扩展,灵活,延迟低,高容错等非功能需求的编排框架。
模型定义
框架需要定义出服务模型,包括请求参数、输出参数、临时变量,流程定义,节点定义,这几个元素。
请求参数:流程需要定义一个输入参数的基类,在开发的过程中请求参数DTO需要继承这个DTO;
输出参数:流程需要定义一个输出参数的基类,在开发的过程中响应参数DTO需要继承这个DTO;
临时变量:用于在流程执行过程中做上下文管理,包括EL表达式解析变量和流程之间参数扭转;
流程定义:需要定义流程标识ID用于标识流程,流程名称用于定义流程别名,请求参数用于定义流程统一输入DTO,输出参数用于定义流程统一响应DTO,临时变量用于上下文管理,流程描述用于描述整个流程的作用,流程节点用于所有节点以Map的形式保存;
节点定义:需要定义节点ID用于标识节点,节点名称用于定义节点别名,请求参数用于定义流程统一输入DTO,输出参数用于定义流程统一响应DTO,节点描述用于描述整个流程的作用,节点类型用于不同的节点类型包括方法节点、bean节点、服务节点、条件节点等,下一个节点标识用过递归的形式执行节点,组件内容,具体指向执行的节点。
这几个模型直接的关系是怎么样的?整个流程模型是一个包含关系,流程定义 = 请求参数+输出参数+临时变量+节点定义+自定义属性;节点定义 = 请求参数+输出参数+自定义属性;我们在日常开发的过程中需要定义请求参数和输出参数分别集成请求参数和输出参数的基类,通过配置文件加载流程定义,也就是说运行期阶段我们只会用到流程定义模型。定义如下:
name: openAccount
id: test
desc: 条件执行
input: com.service.flow.sample.common.model.TestInput
output: com.service.flow.sample.common.model.TestOutput
temp: com.service.flow.sample.common.model.TestTemp
startNode: node1
nodes:
- node:
id: node1
name: methodInvoke
component: com.service.flow.sample.common.component.TestComponent:test1
desc: 单节点执行
input: com.service.flow.sample.common.model.TestInput
type: method
next: node2
- node:
id: node2
name: beanInvoke
component: testComponent:test2
desc: 单节点执行
input: com.service.flow.sample.common.model.TestInput
type: bean
next: node3
- node:
id: node3
name: conditionByAge
component: age>20:node4,age<20:node5
desc: 单节点执行
type: condition
- node:
id: node4
name: beanInvoke
component: testComponent:test4
desc: 单节点执行
input: com.service.flow.sample.common.model.TestInput
type: bean
- node:
id: node5
name: beanInvoke
component: testComponent:test5
desc: 单节点执行
input: com.service.flow.sample.common.model.TestInput
type: bean
流程加载
首先我们要确定流程的几个来源有可能是定义的yml、properties、xml、json或者接口;那我我们设计就要支持流程模式可扩展,不管通过什么方式初始化模型,只要能够转换成流程定义,不管什么方式都是可以,完全用到可扩展的需求;
当然我们也会提供默认的流程加载方式,我们这里以yml格式举例,首先我们需要定义一个yml流程文件,示例如下,新增一个test.flow.yml文件,为了考虑文件路径自定义,也需要把扫描包做成可配置的功能,模式是classpath:flow/*.flow.yml;
平台首先需要定义定一个流程注册接口,所用加载流程模型用于实现流程注册,在通过平台的机制把流程模型加载到流程管理器,具体实现类我们需要对定义的yml流程就行解析,当然规范要严格按照yml的格式定义;在加载的过程中要有异常处理机制,比如定义的节点和参数不存在,重复定义流程;每一个模型的异常处理完全由平台统一管控。
考虑到编写流程文件的便利性,需要提供一种机制需要把所有的DTO和基础组件在应用初始化的过程中加载到组件模型,在定义流程文件的时候不需要定义全路径,而且通过注册的bean映射到具体的实现组件,这样的编排文件就变的更加简单了。
流程解析
我们把节点分为方法节点、bean节点、服务节点、条件节点、循环节点、子流程节点,我们来讲一下主要的设计;
第一步:拿到流程ID,在定义的流程上下文获取流程模型,如果获取不到对应的流程,则抛出对应的异常;
第二步:处理主流程,处理主流程我们需要执行过程就行计时处理,通过解析请求参数和输出参数,上下文并实例化成对象;加载所有的流程节点,并开始查到第一个定义的流程节点;
第三步:节点解析,根据定义的type类型,我们可以知道需要那种节点解析器去做处理;
第四步:节点处理,方法节点很简单通过反射机制调用基础组件;bean节点比方法节点多了一次bean到类的映射,也是通过反射执行组件;条件节点通过EL表达式进行匹配,可配置多个条件,既满足if else场景,也需要满足when case场景;服务节点需要我们自定义实现sdk定义一个轻量级框架,不依赖任务容器,需要在starter模块实现等;
第五步:流程节点执行完成之后会获取下一个节点,然后通过递归的形式调用,有多少节点就递归调用多少次,直到没有下一个节点标识;
第六步:统计执行情况,包括耗时,响应参数;
第七步:异常处理机制,全局可自定义异常处理机制,当流程发生异常时回滚操作;
集成使用
我们参考Spring框架,低侵入松耦合设计思想。编排框架也应该满足这个设计思想。因为框架是需要集成到应用中使用的,我们希望框架尽可能低侵入,与业务代码松耦合,替换、删除起来也更容易些。我们基于Spring框架做集成,并提供starter依赖组件。
相关资源:微服务编排引擎NetflixConductor.zip_微服务流程引擎,流程编排...
————————————————
版权声明:本文为CSDN博主「GEETEST极验」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_29981095/article/details/114622544