近期学习流程 jBPM 引擎时,发现 jBPM 是基于 jBoss 公司的 KIE 工程建设的,所以在学习 jBPM 之前需要弄明白 KIE 工程是什么。KIE 是“Knowledge Is Everything”的简称,KIE 名称也被用于系统的共享方面,比如统一构建、部署和使用。jBoss 公司通过 KIE 将 jBPM 和 Drools 等相关项目进行了一个整合,统一了他们的使用方式。目前 KIE 子工程如下:
KIE 工程或者模块只是一个 Maven Java 项目或者模块,并包括了元数据文件 META-INF/kmodule.xml。kmodule.xml 是为 KIE bases 选择资源,并配置 KIE bases 和 sessions,推荐使用 Mavan 插件 kie-maven-plugin 来构造和打包。
org.kie
kie-maven-plugin
6.2.0.Final
true
KIE 使用默认值来最小化配置量, kmodule.xml 必不可少,空的 kmodule.xml 是最简单的配置,主要用来发现 jar 的内容。KIE 将扫描类路径并查找包含 kmodule.xml 的所有 jar,并使用 KieModule 接口来表示。
csdn:https://download.csdn.net/download/zhuqiuhui/87452118
kie 工程使用比较简单,以 jBPM 流程文件为例,首先需要使用 kie-maven-plugin 插件将资源打成 jar 包并上传到指定仓库,然后应用程序直接从指定仓库拉取,并在每次会话话中使用即可,如下图所示:
以 kie-maven-plugin 插件打包的本地仓库为例,下面示例源码地址:https://download.csdn.net/download/zhuqiuhui/87452118
KIE 工程的生命周期如下图所示,下面重点讲一下构建、部署和运行三个阶段。
KIE 工程构造的过程就是将资源文件打包成 jar 包的过程。Kie 组件(例如 DRL 或 Excel 文件)必须存储在 resources 文件夹或其下的任何其他子文件夹中,编译过程会把这些组件加入到 jar 包中。
构建过程涉及几个核心类:
KieServices 是访问所有 Kie 构建和运行时设施的接口,KieServices 充当集线器的角色为其他服务提供线程安全的单例。
所有 Java 源代码和 Kie 资源都被编译并部署到 KieContainer 中,使其内容可在运行时使用。
KieBase 是应用程序知识定义的存储库。它包含了规则、流程、函数和类型模型。KieBase 本身不包含数据,而是从 KieBase 中创建 sessions,可以在其中插入数据并启动流程实例。KieBase 可以从 KieContainer 中获取或者从已经定义 KieBase 的 kmodule 获取。
KieBase kBase = kContainer.getKieBase();
KieSession 存储和执行运行时数据,如果它已在 kmodule.xml 文件中定义,则它是从 KieBase 中创建或直接 KieContainer 中创建。
像 maven 的 pom 文件定义 ReleaseId 一样,KieModule 是定义 KieBase 的容器,一个 kmodule.xml 文件声明了 KieBase 和 KieSession 相关的配置。
Case 1:使用 kmodule.xml
其中 kmodule.xml 标签的详细解释参考 drools 官方文档:https://docs.jboss.org/drools/release/7.23.0.Final/drools-docs/html_single/index.html#_kiemoduleintroductionbuildingintroductionsection
Case 2:以编程方式来定义 KieModule
当 KieFileSystem 的内容成功构建时,KieModule 结果会自动添加到 KieRepository,KieRepository 是一个单例,用来存储所有的 KieModule(即KieRepository 可以用来增加和删除 KieModule)。
@Test
public void test() {
KieServices kieServices = KieServices.Factory.get();
KieResources resources = kieServices.getResources();
KieModuleModel kieModuleModel = kieServices.newKieModuleModel();//1
KieBaseModel baseModel = kieModuleModel.newKieBaseModel("FileSystemKBase").addPackage("rules");//2
baseModel.newKieSessionModel("FileSystemKSession");//3
KieFileSystem fileSystem = kieServices.newKieFileSystem();
String xml = kieModuleModel.toXML();
System.out.println(xml);//4
fileSystem.writeKModuleXML(xml);//5
fileSystem.write("src/main/resources/rules/rule.drl",
resources.newClassPathResource("kiefilesystem/KieFileSystemTest.drl"));//6
KieBuilder kb = kieServices.newKieBuilder(fileSystem);
kb.buildAll();//7
if (kb.getResults().hasMessages(Level.ERROR)) {
throw new RuntimeException("Build Errors:\n" + kb.getResults().toString());
}
KieContainer kContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
assertNotNull(kContainer.getKieBase("FileSystemKBase"));
KieSession kSession = kContainer.newKieSession("FileSystemKSession");
}
这一步将构建的本地 jar 包 deploy 到远程仓库中,以便在运行中使用。
KieScanner 是 maven 仓库(本地和远程)的扫描器,用于自动发现给定 KieModule 及其依赖项是否有新版本,并最终将它们部署到 KieRepository。使用示例代码如下:
KieServices kieServices = KieServices.Factory.get();
ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "myartifact", "1.0-SNAPSHOT" );
KieContainer kContainer = kieServices.newKieContainer( releaseId );
KieScanner kScanner = kieServices.newKieScanner( kContainer );
// Start the KieScanner polling the Maven repository every 10 seconds
kScanner.start( 10000L );
使用 KieScanner 需要引入 kie-ci 依赖。
KIE 项目运行示例如下:
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieBase kbase = kContainer.getKieBase();
RuntimeManager manager = createRuntimeManager(kbase);
RuntimeEngine engine = manager.getRuntimeEngine(null);
KieSession ksession = engine.getKieSession();
TaskService taskService = engine.getTaskService();
ksession.startProcess("com.sample.bpmn.hello"); // 启动流程实例
List list = taskService.getTasksAssignedAsPotentialOwner("john", "en-UK");
......
以使用 KIE 项目中的 jBPM 为例,在项目中配置参考:
@Configuration
public class JbpmConfig {
@Bean
RuntimeEnvironment runtimeEnvironment(EntityManagerFactory entityManagerFactory) {
return RuntimeEnvironmentBuilder.Factory.get()
.newDefaultBuilder().entityManagerFactory(entityManagerFactory)
.addAsset(ResourceFactory.newClassPathResource("user2.bpmn2"), ResourceType.BPMN2)
.get();
}
@Bean
RuntimeManager runtimeManager(RuntimeManagerFactory runtimeManagerFactory, RuntimeEnvironment runtimeEnvironment) {
return runtimeManagerFactory.newSingletonRuntimeManager(runtimeEnvironment);
}
@Bean
RuntimeEngine runtimeEngine(RuntimeManager runtimeManager) {
return runtimeManager.getRuntimeEngine(EmptyContext.get());
}
@Bean
KieSession kieSession(RuntimeEngine runtimeEngine) {
KieSession kieSession = runtimeEngine.getKieSession();
kieSession.getWorkItemManager().registerWorkItemHandler("Broken", new BrokenWorkItemHandler());
kieSession.getWorkItemManager().registerWorkItemHandler("Human Task", new SystemOutWorkItemHandler());
return kieSession;
}
@Bean
TaskService taskService(RuntimeEngine runtimeEngine) {
return runtimeEngine.getTaskService();
}
//.......
}
核心 uml 图如下:
定义 RuntimeManager 运行时的环境。RuntimeEnvironment 被视为管理器使用的配置模板,该模板是只读的,一旦创建了RuntimeManager,就不能被更改。
RuntimeManager 主要负责管理 RuntimeEngine 的实例并将其交付给调用者,为 process 和 user task 交付可执行环境。此外,RuntimeManager 确保在manager 被实例化后,所有组件(比如 timer service、task service 等)都能被配置和引导,以确保它从一开始就具有完整的功能。
RuntimeManager 提供以下配置策略:
Singleton:无论多少可用的流程,RuntimeManager 只维护单个 KieSession
Per Request:RuntimeManager 为每个请求分别提供 KieSession
Per Process Instance:RuntimeManager 维护流程实例和 KieSession 之间的映射,且每个流程实例对应唯一的 KieSession
RuntimeEngine 是与流程引擎和 task service 交互的主要入口点。它确保流程引擎和 task service 得到正确配置。RuntimeEngine 总是由 RuntimeManager 生成,因此永远不会手动创建。RuntimeEngine 封装了 jBPM 引擎的两个重要的组件:KieSession 和 TaskService。
KieRuntime提供了适用于”规则“和”流程“的方法,例如设置全局变量和注册信道。
从类图中可以发现,所有的 rule 和 process 事件都实现了KieRuntimeEvent。
CommandExecutor 允许在 Session 上执行命令,唯一的区别是 StatelessKieSession 在结束会话之前会自动执行 fireAllRules()方法。示例如下:
StatelessKieSession ksession = kbase.newStatelessKieSession();
ExecutionResults bresults = ksession.execute( CommandFactory.newSetGlobal( "stilton", new Cheese( "stilton" ), true);
Cheese stilton = bresults.getValue( "stilton" );
// 批量命令
StatelessKieSession ksession = kbase.newStatelessKieSession();
List cmds = new ArrayList();
cmds.add( CommandFactory.newInsertObject( new Cheese( "stilton", 1), "stilton") );
cmds.add( CommandFactory.newStartProcess( "process cheeses" ) );
cmds.add( CommandFactory.newQuery( "cheeses" ) );
ExecutionResults bresults = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
Cheese stilton = ( Cheese ) bresults.getValue( "stilton" );
QueryResults qresults = ( QueryResults ) bresults.getValue( "cheeses" );
由于 KIE 项目是 jBPM 和 Drools 等相关项目的整合,KIE API是最顶级的抽象,所以看到核心类会位于不同的依赖中,如 kie-api、jbpm-services-api、drools-core等 jar 包,学习流程引擎时重点需要关注 jbpm 的相关包即可,依赖示意如下:
流程引擎之发展史及对比总结:https://blog.csdn.net/zhuqiuhui/article/details/128986403
流程引擎之KIE项目简介:https://blog.csdn.net/zhuqiuhui/article/details/129035796
流程引擎之jBPM简介:https://blog.csdn.net/zhuqiuhui/article/details/129052162
流程引擎之Activiti简介:https://blog.csdn.net/zhuqiuhui/article/details/129107741
流程引擎之Camunda简介:https://blog.csdn.net/zhuqiuhui/article/details/129107897
流程引擎之Flowable简介:https://blog.csdn.net/zhuqiuhui/article/details/129109273
流程引擎之compileflow简介:https://blog.csdn.net/zhuqiuhui/article/details/129109391
Drools 官方文档有关 KIE 介绍:https://docs.jboss.org/drools/release/7.23.0.Final/drools-docs/html_single/index.html#_kiechapter
drools example github:https://github.com/kiegroup/drools/tree/6.0.x/drools-examples-api