什么是Kogito

Kogito是一个云原生的业务自动化工具包,旨在让你的生活更轻松。可以把它看作是业务流程管理(BPM)和决策管理的结合体,由它的云端父母Quarkus精心培育。

但为什么你,作为一名经验丰富的开发者,应该关注Kogito呢?这里是简要概述:

  • 它是云原生的,并且开箱即用地支持Kubernetes
  • 它与Quarkus完美结合,赋予你超音速、亚原子的Java能力
  • 它将你的业务流程和决策变成代码库中的一等公民
  • 它是开源的,并由Apache软件基金会支持(目前在孵化中)

深入Kogito示例库

现在我们已经引起了你的兴趣,让我们来参观一下apache/incubator-kie-kogito-examples库。这些丰富的示例是你掌握Kogito的通行证。

设置你的Kogito游乐场

在我们深入之前,确保你拥有运行这些示例所需的一切:

  • Java 11+(因为我们不是野蛮人)
  • Maven 3.8.1+
  • Docker(满足容器化的需求)
  • Quarkus CLI(可选,但强烈推荐以提高生产力)

都准备好了吗?太好了!现在让我们动手实践。

Quarkus:Kogito的犯罪搭档

你可能会问,“Quarkus与这有什么关系?”其实,关系重大。Quarkus是超音速、亚原子的Java框架,赋予Kogito云原生的超能力。它就像是Java应用程序的红牛,但没有咖啡因的副作用。

Kogito利用Quarkus来:

  • 实现闪电般的启动时间
  • 减少内存占用(你的钱包会感谢你)
  • 提供热重载功能(因为谁有时间重启呢?)
  • 提供与云原生技术的无缝集成

探索Kogito示例:旋风之旅

让我们来看看库中一些最精彩的示例:

1. 流程 + 规则:动态二人组

导航到kogito-quarkus-examples/process-business-rules-quarkus目录。这个示例展示了Kogito如何结合流程和规则来创建一个强大的决策引擎。

关键要点:

  • 将BPMN2流程与DMN决策表集成
  • 为你的流程自动生成REST端点
  • 在流程上下文中无缝执行规则

2. 无服务器工作流:因为服务器已经过时了

查看serverless-workflow-examples/serverless-workflow-greeting-quarkus示例。这是为所有无服务器爱好者准备的。

亮点:

  • YAML定义的工作流(谁不喜欢YAML呢?)
  • 轻松实现事件驱动架构
  • 与AWS Lambda和Knative的集成

3. DMN:让决策再次伟大

前往kogito-quarkus-examples/dmn-quarkus-example深入了解Kogito中的决策模型和标记(DMN)。

你将学到:

  • 直观地建模复杂的决策逻辑
  • 为你的决策服务自动生成REST API
  • 像专业人士一样测试和调试DMN模型

运行你的第一个Kogito示例:逐步指南

理论够多了,让我们动手实践!我们将使用process-business-rules-quarkus示例来开始。

一旦它运行起来,测试API:

curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"person": {"name":"John Doe", "age": 25}}' http://localhost:8080/persons

构建并运行示例:

./mvnw clean compile quarkus:dev

克隆仓库:

git clone https://github.com/apache/incubator-kie-kogito-examples.git
cd incubator-kie-kogito-examples/kogito-quarkus-examples/process-business-rules-quarkus

瞧!你刚刚使用Kogito执行了一个嵌入规则的业务流程。感受到力量了吗?

实现业务流程:BPMN和DMN,哦我的天!

Kogito将BPMN(业务流程模型和标记)和DMN(决策模型和标记)带入了21世纪。笨重的BPM引擎的日子已经过去了。使用Kogito,你的流程和决策在代码库中是头等公民。

BPMN:增强版流程图

让我们看看一个简单的BPMN流程:

<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" id="_6063f3a1-5ba3-4f0e-b1f2-ad49e8e6f2a7" targetNamespace="http://www.omg.org/bpmn20">
  <bpmn2:process id="greeting" name="Greeting Process" isExecutable="true">
    <bpmn2:startEvent id="_1" name="StartProcess">
      <bpmn2:outgoing>_1-_2</bpmn2:outgoing>
    </bpmn2:startEvent>
    <bpmn2:scriptTask id="_2" name="Hello" scriptFormat="http://www.java.com/java">
      <bpmn2:incoming>_1-_2</bpmn2:incoming>
      <bpmn2:outgoing>_2-_3</bpmn2:outgoing>
      <bpmn2:script>System.out.println("Hello World");</bpmn2:script>
    </bpmn2:scriptTask>
    <bpmn2:endEvent id="_3" name="EndProcess">
      <bpmn2:incoming>_2-_3</bpmn2:incoming>
    </bpmn2:endEvent>
    <bpmn2:sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2"/>
    <bpmn2:sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3"/>
  </bpmn2:process>
</bpmn2:definitions>

这个简单的流程只是打印“Hello World”,但想象一下,当你开始与业务逻辑和外部系统集成时的可能性!

DMN:决策,决策

现在,让我们看看一个DMN模型:

<?xml version="1.0" encoding="UTF-8"?>
<dmn:definitions xmlns:dmn="http://www.omg.org/spec/DMN/20180521/MODEL/" xmlns="https://kiegroup.org/dmn/_52CEF9FD-9943-4A89-96D5-6F66810CA4C1" xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/" xmlns:kie="http://www.drools.org/kie/dmn/1.2" xmlns:dmndi="http://www.omg.org/spec/DMN/20180521/DMNDI/" xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" id="_4F7C97F9-EA35-4CB5-8E4C-C40C91B5F729" name="Greeting" typeLanguage="http://www.omg.org/spec/DMN/20180521/FEEL/" namespace="https://kiegroup.org/dmn/_52CEF9FD-9943-4A89-96D5-6F66810CA4C1">
  <dmn:decision id="_23B84E59-33C6-4D3A-9314-CF0724714606" name="Greeting Message">
    <dmn:extensionElements/>
    <dmn:variable id="_078A6F79-1861-47A1-8921-C9E7F2B728D1" name="Greeting Message" typeRef="string"/>
    <dmn:informationRequirement id="_2066A270-2A88-4B77-9F90-1F683FDF852C">
      <dmn:requiredInput href="#_C7ED7EFC-9F7F-4FBE-81DB-57A32A56502C"/>
    </dmn:informationRequirement>
    <dmn:decisionTable id="_5A25D948-34E0-4527-9EE2-7A9C0DC663A5" hitPolicy="UNIQUE" preferredOrientation="Rule-as-Row">
      <dmn:input id="_79ECD1F2-E11E-4F6D-9038-C47AE6EC1C9C">
        <dmn:inputExpression id="_E17A0C1D-A0F0-4C5F-8A0E-8B5F9A1BAB08" typeRef="number">
          <dmn:text>Age</dmn:text>
        </dmn:inputExpression>
      </dmn:input>
      <dmn:output id="_EC6A4902-BD03-4D48-AA45-9AD2AEB83E8B"/>
      <dmn:annotation name="annotation-1"/>
      <dmn:rule id="_C3F28427-2608-4ACE-98EE-C5C2F0AEF7A7">
        <dmn:inputEntry id="_0FBE3F3C-5F3A-4A21-A4A5-D207B2BA7808">
          <dmn:text>< 18</dmn:text>
        </dmn:inputEntry>
        <dmn:outputEntry id="_C05BE7BB-BDA0-4C45-9ED1-4F5B17B2A3E6">
          <dmn:text>"Hello young person!"</dmn:text>
        </dmn:outputEntry>
        <dmn:annotationEntry>
          <dmn:text/>
        </dmn:annotationEntry>
      </dmn:rule>
      <dmn:rule id="_C3B07D74-0354-4C44-9587-9B44C67F5AE0">
        <dmn:inputEntry id="_8A9B0EEC-5CB9-4D31-BB56-0A723CEABFBC">
          <dmn:text>>= 18</dmn:text>
        </dmn:inputEntry>
        <dmn:outputEntry id="_42C4EB7F-3F00-4A19-9F43-D2E246F378F9">
          <dmn:text>"Hello adult!"</dmn:text>
        </dmn:outputEntry>
        <dmn:annotationEntry>
          <dmn:text/>
        </dmn:annotationEntry>
      </dmn:rule>
    </dmn:decisionTable>
  </dmn:decision>
  <dmn:inputData id="_C7ED7EFC-9F7F-4FBE-81DB-57A32A56502C" name="Age">
    <dmn:extensionElements/>
    <dmn:variable id="_F0B70F13-94CB-4FB9-BD89-4AB84F8BDB07" name="Age" typeRef="number"/>
  </dmn:inputData>
  <dmndi:DMNDI>
    <dmndi:DMNDiagram>
      <di:extension>
        <kie:ComponentsWidthsExtension>
          <kie:ComponentWidths dmnElementRef="_5A25D948-34E0-4527-9EE2-7A9C0DC663A5">
            <kie:width>50</kie:width>
            <kie:width>100</kie:width>
            <kie:width>100</kie:width>
            <kie:width>100</kie:width>
          </kie:ComponentWidths>
        </kie:ComponentsWidthsExtension>
      </di:extension>
      <dmndi:DMNShape id="dmnshape-_23B84E59-33C6-4D3A-9314-CF0724714606" dmnElementRef="_23B84E59-33C6-4D3A-9314-CF0724714606" isCollapsed="false">
        <dmndi:DMNStyle>
          <dmndi:FillColor red="255" green="255" blue="255"/>
          <dmndi:StrokeColor red="0" green="0" blue="0"/>
          <dmndi:FontColor red="0" green="0" blue="0"/>
        </dmndi:DMNStyle>
        <dc:Bounds x="364" y="227" width="100" height="50"/>
        <dmndi:DMNLabel/>
      </dmndi:DMNShape>
      <dmndi:DMNShape id="dmnshape-_C7ED7EFC-9F7F-4FBE-81DB-57A32A56502C" dmnElementRef="_C7ED7EFC-9F7F-4FBE-81DB-57A32A56502C" isCollapsed="false">
        <dmndi:DMNStyle>
          <dmndi:FillColor red="255" green="255" blue="255"/>
          <dmndi:StrokeColor red="0" green="0" blue="0"/>
          <dmndi:FontColor red="0" green="0" blue="0"/>
        </dmndi:DMNStyle>
        <dc:Bounds x="365" y="94" width="100" height="50"/>
        <dmndi:DMNLabel/>
      </dmndi:DMNShape>
      <dmndi:DMNEdge id="dmnedge-_2066A270-2A88-4B77-9F90-1F683FDF852C" dmnElementRef="_2066A270-2A88-4B77-9F90-1F683FDF852C">
        <di:waypoint x="415" y="119"/>
        <di:waypoint x="414" y="252"/>
      </dmndi:DMNEdge>
    </dmndi:DMNDiagram>
  </dmndi:DMNDI>
</dmn:definitions>

这个DMN模型根据一个人的年龄决定问候语。这是一个简单的例子,但想象一下将其扩展到复杂的业务规则和决策过程!

自定义规则和决策:按你的方式或高效方式

Kogito不仅提供开箱即用的规则和决策。它还允许你根据独特的业务需求进行定制。以下是一些定制方法:

1. Drools规则语言(DRL)

当视觉模型无法满足需求时,你可以使用传统的DRL:

package org.acme.rules

import org.acme.model.Person

rule "Greet adults"
when
    $person: Person(age >= 18)
then
    System.out.println("Hello, responsible adult!");
end

rule "Greet children"
when
    $person: Person(age < 18)
then
    System.out.println("Hi, youngster! Where are your parents?");
end

2. 决策表

对于那些看到代码就过敏的业务用户,决策表是福音:

RuleSet,org.acme.rules
RuleSetName,Greeting Rules

RuleTable Greeting
CONDITION,ACTION
Person.age,System.out.println
>=18,"Hello, responsible adult!"
<18,"Hi, youngster! Where are your parents?"

3. 使用自定义函数扩展DMN

需要在DMN模型中增加一些额外的功能?用自定义Java函数扩展它们:

@DMNFunction(name = "toUpperCase")
public static String toUpperCase(String input) {
    return input.toUpperCase();
}

现在你可以在DMN表达式中使用toUpperCase()。很酷吧?

将Kogito与外部世界集成

Kogito与其他系统配合得很好。让我们看看如何将它与一些流行的外部系统集成:

REST API:因为SOAP是用来洗的

Kogito自动为你的流程和决策生成REST端点。但如果你需要调用外部REST API呢?轻而易举:

@Inject
RestClient myExternalService;

@POST
@Path("/process")
public Response startProcess(ProcessPayload payload) {
    // 启动你的Kogito流程
    ProcessInstance<?> processInstance = processService.createProcessInstance(...);
    
    // 调用外部REST API
    ExternalData data = myExternalService.getData(payload.getId());
    
    // 更新流程变量
    processInstance.updateVariables(Collections.singletonMap("externalData", data));
    
    return Response.ok(processInstance).build();
}

Kafka:为那些事件驱动的时刻

Kogito和Kafka就像花生酱和果冻一样搭配。这里是一个例子:

@Inject
Emitter<PersonEvent> personEventEmitter;

@POST
@Path("/persons")
public Response createPerson(Person person) {
    // 你的Kogito流程逻辑在这里
    
    // 向Kafka发送事件
    personEventEmitter.send(new PersonEvent(person));
    
    return Response.ok(person).build();
}

别忘了在application.properties中配置你的Kafka连接:

mp.messaging.outgoing.person-events.connector=smallrye-kafka
mp.messaging.outgoing.person-events.topic=person-events
mp.messaging.outgoing.person-events.value.serializer=io.quarkus.kafka.client.serialization.JsonbSerializer

调试Kogito:当事情出错时

即使是最好的开发者有时也会陷入调试困境。这里有一些保持理智的技巧:

1. 启用调试日志

首先,增加日志记录:

quarkus.log.category."org.kie".level=DEBUG
quarkus.log.category."org.drools".level=DEBUG
quarkus.log.category."org.jbpm".level=DEBUG

2. 使用Kogito开发UI

Kogito带有一个时尚的开发UI。只需添加这个依赖项:

<dependency>
    <groupId>org.kie.kogito</groupId>
    <artifactId>kogito-addons-quarkus-process-management</artifactId>
</dependency>

现在你可以访问http://localhost:8080/q/dev来查看你的流程和决策的运行情况。

3. 测试,测试,测试

单元测试是你的朋友。这里是一个快速示例:

@QuarkusTest
public class GreetingProcessTest {

    @Inject
    ProcessService processService;

    @Test
    public void testGreetingProcess() {
        ProcessInstance<?> processInstance = processService.createProcessInstance(
            "greeting",
            Collections.singletonMap("name", "John")
        );
        
        assertThat(processInstance.status()).isEqualTo(ProcessInstance.STATE_COMPLETED);
        assertThat(processInstance.variables()).containsEntry("greeting", "Hello, John!");
    }
}

性能调优:让它飞速运行

Kogito已经很快了,但通过这些技巧,你可以让它突破音障:

1. 原生编译

Quarkus提供原生编译,可以显著减少启动时间和内存使用:

./mvnw package -Pnative

2. 响应式编程

采用响应式范式以获得更好的可扩展性:

@Inject
ReactiveProcessService processService;

@POST
@Path("/process")
public Uni<ProcessInstance<?>> startProcess(ProcessPayload payload) {
    return processService.createProcessInstance("myProcess", payload.toMap());
}

3. 缓存

使用Quarkus的内置缓存功能来加速频繁操作:

@CacheResult(cacheName = "greeting-cache")
public String getGreeting(String name) {
    // 耗时操作在这里
    return "Hello, " + name + "!";
}

最佳实践:该做和不该做的事

让我们以一些Kogito开发的黄金法则来结束:

该做:

  • 保持你的流程和决策简单且模块化
  • 为你的BPMN和DMN元素使用有意义的名称
  • 利用Quarkus的热重载进行快速开发
  • 记录你的流程和决策(你的未来自我会感谢你)
  • 为你的BPMN和DMN文件使用版本控制

不该做:

  • 不要在你的流程图中放置业务逻辑(使用服务任务代替)
  • 不要忽视流程中的错误处理
  • 不要忘记监控和可观察性
  • 不要忽视安全最佳实践(Kogito不是神奇的安全粉尘)

真实世界的Kogito:不仅仅是个漂亮的面孔

Kogito不仅仅用于玩具示例。它在野外被用于一些严肃的业务自动化。以下是一些真实世界的应用:

  • 金融服务:自动化贷款审批流程和欺诈检测
  • 医疗保健:管理患者工作流和保险索赔处理
  • 电子商务:协调订单履行和退货流程
  • 制造业:优化供应链决策和质量控制流程

为Kogito做贡献:加入酷小孩俱乐部

感到灵感了吗?想要回馈社区?以下是你可以为Kogito做贡献的方法:

  1. Fork Kogito示例库
  2. 问题跟踪器中选择一个问题
  3. 进行更改并提交拉取请求
  4. 邮件列表上与社区互动

记住,没有贡献是太小的。即使是修正文档中的一个错字也会受到赞赏!

最后倒计时:总结

这就是全部,朋友们!Kogito及其超能力的旋风之旅。我们涵盖了从设置你的第一个Kogito项目到为开源社区做贡献的一切。

Kogito,由Quarkus驱动,正在改变业务自动化的游戏规则。它将云原生技术的力量带入业务流程和决策的世界。无论你是在构建一个简单的工作流还是一个复杂的决策系统,Kogito都能满足你的需求。

那么,你还在等什么?深入研究,开始实验,加入Kogito革命。你的未来自我(以及你的运维团队)会感谢你。

记住:能力越大,责任越大。明智地使用Kogito,愿你的业务流程永远对你有利!