关于java:Kstry流程编排框架

150次阅读

共计 7358 个字符,预计需要花费 19 分钟才能阅读完成。

    🟢 我的项目主页

    🟢 Kstry 概念介绍

    🟢 Kstry 应用文档

    🟢 Kstry 应用 demo

    🟢 Kstry 流程注解 +flux 应用 demo

    🟢 功能测试

Kstry 是什么?

    Kstry 能够将本来存在于代码中盘根错节的办法调用关系以可视化流程图的模式更直观的展现进去,并提供了将所见的办法节点加以控制的配置伎俩。框架不能脱离程序执行之外存在,只能在办法与办法的调用中失效和应用,比方某个接口的一次调用。不会像 Activiti、Camunda 等工作流框架一样,脱离程序执行之外将工作实例存储和治理。

    不同应用场景中,因其发挥作用的不同,能够了解成不同的框架,Kstry 是:

    🟢【流程编排框架】提供所见(流程图示)即所得(代码执行)的可视化能力,可自定义流程协定,反对流程配置的热部署

    🟢【并发框架】可通过极简操作将流程从串行降级到并行,反对工作拆分、工作重试、工作降级、子工作遍历、指定流程或工作的超时工夫

    🟢【微服务业务整合框架】反对自定义指令和工作脚本,可负责各种根底能力组件的拼装

    🟢【轻量的 TMF2.0 框架】能够通过以下三个步骤来满足同一接口下各类业务对实现性能的不同诉求:形象能力资源、定义并将形象出的能力资源受权给业务角色、同一流程的不同场景可别离匹配不同角色再将其下的能力资源工作加以执行

Kstry 有哪些特点?

    🟢【业务可视 】编排好的图示模型即为代码实在的执行链路,通过所见( 图示模型 )即所得( 代码执行)的形式在技术和业务之间架起一道通用语言的桥梁,使彼此之间沟通更加顺畅

    🟢【配置灵便】提供开始事件、完结事件、服务节点、脚本节点、排他网关、蕴含网关、并行网关、条件表达式、自定义指令、子流程、拦截器等配置组件,能够反对变态简单的业务流程

    🟢【动静配置】主流程、子流程、角色、变量等组件反对动态化配置,不启动利用的前提下能够动静变更,动态化配置反对包含开源和公司自研在内的全副存储介质

    🟢【适配度高】蕴含 BPMN 可视化配置文件和代码两套流程定义 API,在保障可视化配置的前提下,又反对通过代码形式解析任意格局的流程配置文件,从而联合适合的前端产品搭建个性化的流程配置平台

    🟢【轻松运维】服务节点反对定义超时工夫、重试次数、失败降级、严格模式、资源迭代等,可满足生产环境下对利用稳定性的严苛要求

    🟢【性能优异】最底层采纳 Spring 工具集进行服务节点调用,工作执行耗费与 Spring 切面相当

    🟢【秒变异步】无缝连接 SpringFlux。无需改变代码,仅仅在并行网关或蕴含网关上配置 open-async=true,即可在保障线程平安的前提下将其后的子链路全副并行化

    🟢【交互顺畅】引入 StoryBus 和其中四个数据域的概念。节点之间数据存取交互能够做到平安、灵便、不便

    🟢【业务形象】引入资源、权限、角色等概念,构建定制化业务身份,为抽象化业务能力提供技术支持和解决方案

    🟢【流程回溯】能够零老本记录节点执行程序、节点耗时、入参、出参、异样信息等重要数据,并反对自定义执行监控日志

Kstry 能够解决哪些问题?

    🟢【业务含糊】代码简单、模型文档更新不及时,以致新同学和非技术同学不能短时间内理解业务现状。技术和非技术间对同一业务了解存在一致而不自知。甚至业务 Owner 也不能很晦涩的形容出本人所负责的业务

    🟢【代码芜杂】我的项目中波及到许多畛域对象,对象间不仅存在简单的前后依赖关系还互相掺杂没有显著边界,代码屡次迭代后更是凌乱不堪难以保护

    🟢【性能低下】某业务链路由一系列子工作组成,其中须要并行处理一些耗时长且数据间没有依赖的子工作,但苦于没有精简且无代码侵入的并发框架

    🟢【平台之殇】保护平台型产品,为泛滥上游业务线提供着根底服务,但在短时间内应对各个业务方的定制化需要顾此失彼,更不知如何做好平台与业务、业务与业务之间的隔离

    🟢【回溯艰难】业务流转数据状态追踪艰难,只存在于线上环境的偶现问题更是难以排查。须要一种能够通过简略操作就能将重要节点数据都保留下来的能力,此能力堪比对链路精细化梳理后的系统性日志打印

    🟢【测试简单】业务场景多样,不乏一些简单的链路难以被测试笼罩。或者三方数据 Mock 艰难,测试老本居高不下

Kstry 组件概念介绍

1、配置域与运行域

    简略来讲配置域就是通过可视化、代码亦或者脚本的形式配置流程,执行域就是依据配置好的规定来执行。

    概念上了解,通常状况下的程序执行是办法与办法之间的调用,在 Kstry 中却是工作节点之间的互相关系(之所以是概念上来看,是因为无论是否用 Kstry,程序理论执行载体都是类中的办法,而且工作节点与办法也是一一对应的)。工作执行前的流程配置决定了节点之间在理论执行时会产生何种关系。程序未执行前的流程配置就是配置域,框架解析流程配置并在程序执行时领导工作节点先后调用就是执行域。

2、流程定义

    流程定义是程序理论执行前,在配置域须要实现的工作,由开始事件、完结事件、服务节点、网关、及这些组件相连接的有向线段独特组成。编排好的图示模型即为代码实在的执行链路,通过所见(图示模型 )即所得( 代码执行)的形式在技术和业务之间架起一道通用语言的桥梁,使彼此之间沟通更加顺畅。

    只有 bpmnPath 一种流程配置路径时,上面这种可视化流程图就是被定义进去的流程,也是凭此来领导程序理论线路的执行。ProcessLink呈现之后,框架提供了自定义流程的能力给使用者,在 1.x 之后的版本中,BPMN 可视化流程图也是被解析成 ProcessLink 对象来失效的,此时的 BPMN 可视化流程就作为了流程定义的一个子集而存在。更多状况下使用者能够通过编码、解析各类配置文件等形式来创立 ProcessLink 实例,最终交付给框架的 ProcessLink 实例将会作为流程定义来领导程序的执行。

    Kstry 提供了三种形式来定义流程配置,别离是:

    🟢【根底流程配置 】指定@EnableKstry 注解的 bpmnPath 属性来扫描指定目录下的 bpmn 配置文件

    🟢【根底流程配置 】创立ProcessLink 实例放入 Spring 容器中

    🟢【动静流程配置 】实现DynamicProcess 接口的 getProcessLink 办法

    后面两种形式定义的流程是利用启动前就必须要定义进去的属于根底流程配置,根底流程除非利用重启否则是不容许批改的。依据 startId 在根底流程配置库里获取不到流程配置时最初一种形式才会失效,其获取流程配置的形式是动静的,传入 startId 返回 ProcessLink 实例,其中所需的流程配置信息能够通过 http 或 rpc 调用、关系或者非关系型数据库查问、订阅音讯队列、订阅注册核心、公司自定义存储介质查问等任意形式获取。

    之所以没有应用动静扭转根底流程配置库的形式来实现流程的动静配置能力,有以下起因:

    🟢【安全性 】流程配置可能会分重要级别,外围的流程配置是被严格管控不容许随便变更的,所以这类配置应该放在代码中不容许随便变更。如果在流程配置根底库中找到与startId 相匹配的流程,动静获取局部将生效,以此来保障流程的相对平安。即使外围流程中有局部须要动静获取的扩大逻辑,也能够用动静子流程的模式来实现。

    🟢【兼容性】动态化配置可能比拟适宜应用注册核心来存储保护,这样当产生变更时能疾速及时告诉相干利用做流程变更。但并没有一个注册核心是所有公司都应用的,除了开源产品还有公司自研,如果想要一一反对是不事实的。选用其余中间件产品也是同样的情理。所以解决这个问题的形式就是提供一个动静获取流程配置的入口,至于流程配置在什么中央获取将是因人而异的。

3、子流程定义

    顾名思义,子流程概念很好了解。在流程中呈现可复用或者简单的链路片段时,就能够将这些片段抽离进去定义子流程。父流程能够通过子流程 Id 来援用子流程。同样也有三种形式来定义子流程,别离是:

    🟢【根底子流程配置 】指定@EnableKstry 注解的 bpmnPath 属性来扫描指定目录下的 bpmn 配置文件

    🟢【根底子流程配置 】创立SubProcessLink 实例放入 Spring 容器中

    🟢【动静子流程配置 】实现DynamicSubProcess 接口的 getSubProcessLinks 办法

    主流程有根底和动静之分,绝对应也有根底和动静子流程的存在。下图为两者联合起来时,相互之间是否容许被援用的阐明:

    🟢 根底流程仅能援用根底子流程配置,动静流程能够援用根底子流程和动静子流程配置

    🟢 两种子流程在各自的区域内能够互相援用,动静子流程中能够援用根底子流程配置,反之则不被容许

::: danger 正告
子流程相互间援用时,肯定不能呈现环状依赖,否则会出现异常
:::

4、服务节点

    框架通过定义服务节点来划分畛域边界并实现业务性能。服务节点是流程编排和工作执行的最小单元。配置域内一个个被有向线段连接起来的服务节点组成了主流程或者子流程。运行域中节点对应类组件中的某个办法,流程执行实际上是与节点绝对应的办法被一一调用的过程。

    框架中如果要定义服务节点,首先须要定义服务节点(也就是办法)所在的组件类。组件类都是托管在 Spring 容器中的,有两种定义形式:

    🟢 类放在 Spring 容器能够扫描到的地位,并增加 @TaskComponent 注解

    🟢 以 Spring 组件的形式被加载,并实现 TaskComponentRegister 接口

    组件类被定义之后,其内的私有办法加上 @TaskService 注解就是服务节点。@TaskService注解中的 @Invoke 属性能够指定服务节点重试次数、超时工夫、降级办法、异样后 Story 是否被容许继续执行等

::: warning 正告
@TaskService 润饰的办法必须是 public 的,否则无奈辨认
:::

    正如后面所说的,Kstry 即是流程编排框架,也是轻量的 TMF2.0 框架。服务节点的了解形式相关联的也有两种思路:

    🟢 仅仅只是流程编排的话,能够将整个流程看作一个残缺的工作,服务节点就是其中的子工作

    🟢 另一种思路更实用于平台型产品。能够将一个残缺的流程定义看作是平台针对某个业务流动提供的解决方案。服务节点就是解决方案中的服务(下图中,加载商品信息、店铺信息、营销信息、计算价格都是服务),服务下能够定义多个能力点,在代码维度来看就是标注 @TaskService 注解的办法中,name属性雷同的服务节点为同一个服务,不同的 ability 属性辨别出了不同的能力点。针对不同业务能够匹配各服务下的不同能力点来实现个性化业务诉求。其中波及到的更具体概念能够查看上面能力 & 角色的介绍

        

    无论哪种思路,服务节点的划分准则都是尽可能的做到业务隔离。一次业务申请通过各种业务流动最终拿到后果的过程是动静的,应用边界将动静的业务流程进行正当切分,其产物就是服务节点也是畛域驱动中的限界上下文。了解以下限界上下文的特点,能够领导如何更好的定义服务节点:

        

    🟢 最小齐备:具备实现本身使命指标的最小依赖条件,无需求助其余的服务节点,防止不必要的依赖

    🟢 自我履行:依据服务节点本人现把握的资源信息,判断预期指标与本身的使命指标是否相符,决策是否应该履行该职责

    🟢 稳固空间:缩小外界变动对服务节点外部的影响

    🟢 独立进化:缩小服务节点的变动对外界的影响

5、网关

    网关有三种:排他网关、蕴含网关、并行网关

    网关有管制流程执行的作用,不同网关有着不同的特点,蕴含网关和并行网关还能够配置其后的流程并发执行。各类网关与服务节点联合起来应用能够实现非常复杂的业务场景

#### 5.1 排他网关

    🟢 排他网关只能接管一个入度。也就是说有且只能有一个箭头能够指向排他网关。这点上服务节点也是如此

    🟢 排他网关入度只能有一个,出度能够多个。出度下面的条件表达式会被解析执行,如果没有条件表达式会默认是 true

    🟢 排他网关有多个出度相干的表达式被解析成 true 时,会抉择第一个为 true 的分支持续向下执行,其余的将会被疏忽不再执行。出度的前后并不代表程序解析时出度的先后顺序,所以排他网关前面 如果多个出度都为 true 时运行后果是不确定的,应尽量避免这种事件产生

    🟢 当全副出度上的表达式都解析为 false 时会抛出异样并完结流程

    🟢 因为排他网关前面最终执行的只有一条链路,所以排他网关是不反对开启异步的,因为没啥意义

5.2 并行网关

    🟢 并行网关能够接管归并多个入度

    🟢 并行网关要求所有入度全副执行完能力持续,否则将始终期待。所以应用前须要确认网关的全副入度肯定都是可达的

    🟢 应用并行网关时,个别前后两个并行网关会一起呈现。后面将一个分支拆解成多个,前面将多个分支进行聚合

    🟢 并行网关反对开启异步流程。未开启异步时,并行网关拆分出的多个分支还是被以后线程执行,开启异步流程后,网关前面所有分支都会创立异步工作并提交到线程池中执行

    🟢 并行网关前面的出度如果有条件表达式,表达式会被疏忽,无论设置与否都不会解析,都会默认为 true

5.3 蕴含网关

    🟢 蕴含网关与并行网关一样,反对开启异步流程,反对接管多个入度

    🟢 蕴含网关没有全副入度必须达到的限度,期待全副入度执行实现或者得悉其中可能有局部入度不满足条件不再执行后,会持续向下

    🟢 蕴含网关前面出度能够设置条件表达式,表达式解析规定与排他网关出度解析规定雷同

6、流程 Story

    流程定义形容当下的这个流程如何执行属于配置域内容,而流程 Story 则是依据定义好的流程进行的一次次执行,属于运行域内容。两者能够了解成代码中类定义与对象实例的关系,流程定义就是类文件来形容对象的状态内容,对象则是依据类文件创建出的一个个实例。

    框架提供 StoryEngine 实例来解析流程执行 Story,该实例托管在 Spring 容器中,能够应用任意获取 Spring Bean 的形式来获取 StoryEngine 对象。对象提供同步和异步两种形式来执行 Story,值得一提的是,无论同步和异步执行前是肯定会被设置超时工夫的,超时工夫默认是 3s。耗时高场景或 debug 代码时能够依据须要调大到适合的超时工夫。

7、StoryBus

    流程定义中的服务节点是一个个的独立个体,相互之间不会存在任何的依赖关系,数据也就更无奈间接进行传递。然而一次业务诉求又是各节点间通力合作相互配合来实现的,此时就须要理解 StoryBus 这个概念了。StoryBus 是流程 Story 的数据总线,生命周期也会和流程 Story 保持一致。

    🟢 每一个服务节点都能够从 StoryBus 中获取须要的参数,执行完之后,再将须要的后果告诉到 StoryBus

    🟢 StoryBus 中有四个数据域,别离是:

        🔷 req:保留申请传入的 request 对象,request 对象自身不会发生变化。但对象外面的值容许通过前期的变量告诉产生更新

        🔷 sta:保留节点执行实现后产生的变量,一经设置,将不再发生变化,如果呈现反复设置会有正告日志(当只有对象的援用在 sta 域时,对象外面的字段还是能够产生更新的,这点与 req 雷同)

        🔷 var:保留节点执行实现后产生的变量,能够被反复替换,对象外面的字段性质同上

        🔷 res:保留最终后果,作为 Story 执行实现后最终的后果返回给调用者(1.0.9 版本开始,result 更名为 res

    🟢 服务节点通过注解(@NoticeXxx@XxxTaskParam@XxxTaskField Xxx 泛指下面提到的四个域 )和ScopeDataOperator 两种形式来从 StoryBus 中存取变量

    🟢 节点出度中,能够定义条件表达式间接援用这四个域做条件判断,如流程编排中呈现的:res.img != nullreq.source!='app'

    🟢 四个作用域被读写锁爱护着,get 获取读锁,notice 获取写锁,防止出现并发问题

    🟢 开启异步模式后,同时创立的子工作都能够读写 StoryBus 中的变量,所以 数据方面有前后依赖关系的节点,不能被创立到同一时间段执行的不同子工作中,有相干诉求时能够通过聚合节点来保障节点执行时数据的先后依赖程序

8、能力 & 角色

  • 针对平台型服务,首先能够定义编排出通用的链路模型,也就是下面说的流程定义
  • 模型中的某个服务节点,应答不同业务场景或需求方的诉求时,能够扩大不同的服务能力(比方 A、B 两个业务方都须要抽佣的服务,那么就能够定义一个抽佣的服务节点,而后 A 业务须要比例抽佣,而 B 业务须要阶梯式抽佣,这时就能够在抽佣的服务节点上再扩大两个不同的抽佣能力
  • 扩大进去的能力可视作资源,所有的资源都有着举世无双的资源名称,携带着蕴含某个资源名称的权限对象即可拜访与之对应的资源(资源也可称为:扩大进去的服务能力
  • 一批独立的权限对象有着较高的保护老本,所以可顺次将某一业务场景所需的全副权限聚合起来组成角色对象
  • 提供平台能力时,依据参数标识判断出具体的业务场景或需求方,并找到与之对应的角色,携带该角色执行预设的链路模型,即可实现定制化的业务诉求

    详见:RBAC 模式

9、流程回溯

    流程回溯能够在链路执行完之后,拿到后果或者异样之前,打印节点执行日志或执行自定义回调办法,能够应答如下问题:

    🟢 查看运行过节点的信息如:执行程序、节点耗时、入参、出参、异样信息等重要数据

    🟢 自定义流程回溯日志,或者能够在出现异常时才打印详情日志

    🟢 查看节点执行、参数设置等是否合乎预期。因为有时后果的确没有报错,但并不代表过程肯定没有问题

    🟢 如果链路中有自定义角色的操作,查看最终角色是否合乎预期

正文完
 0