流程引擎技术

将流程引擎比喻为“工厂生产线”可以帮助更好地理解它的工作机制和作用。以下是这个比喻的详细解释:

工厂生产线比喻

1. **工厂整体结构**:
   - 就像工厂有多个部门(生产、质检、包装等),流程引擎有多个步骤和任务,每个步骤代表流程中的一个环节。这些步骤能够根据预设的逻辑有序进行。

2. **原材料与产品**:
   - 流程引擎处理的数据和信息可以看作工厂的原材料,而经过一系列处理后的结果则相当于成品。原材料经过多个环节(步骤)后,最终形成可以交付给客户的成品。

3. **流水线**:
   - 工厂的流水线是为了确保各个工序按顺序、有效率地进行。流程引擎也有类似的作用,将任务按照定义好的顺序逐一执行。当一个步骤完成后,自动将结果传递到下一个步骤。

4. **工人**:
   - 在生产线上,工人执行特定的任务,以确保产品按照标准生产。相应地,流程引擎中的每个任务也是由系统(或人)负责执行,参与到整体流程中。

5. **控制中心**:
   - 工厂通常有一个监控系统来监督生产线上的各项活动并确保工人和设备的运作。同样,流程引擎有控制和监控功能,能够跟踪流程状态、监控任务执行情况,以及及时处理异常情况。

6. **规则和规范**:
   - 工厂操作遵循一定的标准和规范,以确保产品生产的一致性与质量。流程引擎同样也需要遵循预设的业务逻辑和规则,确保每个步骤的执行符合业务需求。

7. **反馈机制**:
   - 在工厂中,生产过程中可能会有质量反馈,工人可以根据反馈调整操作。流程引擎在设计上也支持反馈机制,可以根据业务变更或执行结果调整流程执行的路径。

 具体示例

假设我们有一个 **订单处理** 的流程引擎:

- **接收订单**(原材料) →  **验证支付**(工人1) →  **检查库存**(工人2) →  **发货**(工人3) → **订单完成**(成品)。

在这个过程中,每一个步骤都依赖于前一个步骤的完成,并且都遵循一定的业务规则(例如,只有在支付成功后才能检查库存)。如果在任何一个环节中出现问题(例如,库存不足),流程引擎会根据预设的规则做出相应的处理(例如,通知客户发货延迟)。

 总结

通过将流程引擎比作工厂生产线,我们可以清晰地看到它在管理和优化业务流程中的重要性。它通过规范化的步骤和高效的自动化帮助组织提高效率、降低错误,并为最终用户提供更好的服务。这个比喻有助于更好理解流程引擎的核心功能和优势。

什么是流程引擎

流程引擎是一个底层支撑平台,是为提供流程处理而开发设计的。流程引擎和流程应用,以及应用程序的关系如下图所示。

常见的支撑场景有:Workflow、BPM、流程编排等。本次分享,主要从 BPM 流程引擎切入,介绍流程引擎的架构设计方法。

1.1 什么是流程

简单来说,流程就是一系列活动的组合。比如,用于企业办公的 OA 系统中,就存在大量的申请审批类的流程。在生产制造业,有大量的从销售端的订单,到生产制造,再到签收回款的生产销售流程。在机器学习领域,有亚马逊 AWS Sagemaker 的大数据处理、机器学习的应用。综上,流程是一个概念,在和具体实现结合时,就产生了不同的流程产品,如 DevOps、Spring Data Stream 等。
在流程实现方面,主要可以分为 2 种实现方式,一种是用代码实现,比如:用代码实现一个加班申请,那么就要自己对接 SSO 进行单点登录,通过接口拿到发起人和审批人的信息,同时保存表单数据。另一种方式是使用流程引擎来实现,流程引擎对接应用场景所需数据,如加班申请,流程引擎对接 SSO、OU、审批人配置、权限等,实现这样一个流程,只需要关心流程配置、流程节点和流程表单即可,流程流转以及流程的数据处理,都通过流程引擎来完成。
流程引擎可以快速落地流程实现,这也是流程引擎存在的价值。

1.2 什么是引擎

一般而言,引擎是一个程序或一套系统的支持部分。常见的程序引擎有游戏引擎、搜索引擎、杀毒引擎等。引擎是脱离具体业务场景的某一类业务场景的高度抽象和封装。
比如,某 OA 公司,封装了一套审批用的 workflow,实施人员只需要配置流程和表单即可交付项目。再比如,美国某公司做了一个 AI 引擎做 NBA(Next Best Action)推荐,封装了推荐领域的常用算法,在不同的场景自动选择和组合多种算法,进行智能推荐。

1.下载和安装

首先,您需要安装 Camunda BPM平台和Camunda Modeler。

前期准备

确保你具有 JAVA1.8以上的JRE或JDK,并可以在命令行使用

在命令行中运行以下命令,检查你的java版本

java -version

可以在 Camunda’s support list 里找到Camunda支持的所有JAVA版本

Camunda Platform (Camunda BPM平台)

首先我们需要下载 Camunda Platform

打开下载地址 https://camunda.com/download/

下载ZIP压缩包,并解压到任意位置

windows运行start.batlinux运行start.sh,脚本会启动服务

在浏览器中打开 http://localhost:8080/ 就可以看到欢迎页面了

Camunda Modeler(用于编辑流程图及其他模型)

打开下载地址 https://camunda.com/download/modeler/

下载对应系统的版本,并解压到任意位置

执行 camunda-modeler.exe (Windows), camunda-modeler.app (Mac), or camunda-modeler.sh (Linux),即可启动Camunda Modeler

2.编辑流程

本章中,我们将会使用Camunda Modeler创建第一个BPMN 2.0流程,并执行一些自动任务

首先,打开Camunda Modeler

新建BPMN流程

点击 File > New File > BPMN Diagram ,创建一个新的流程设计文件

编辑一个简单的流程

  1. 双击 开始 节点编辑标签,输入“付款请求”
标签可以换行,需要使用Shift +回车
  1. 点击右面显示的方框,添加一个新的活动

可以看到一个新的活动显示到画布上,双击将它命名为“刷卡付款”

  1. 点击取信用卡节点右面的扳手可以修改活动类型,这里我们修改为Service Task(服务类型)

  1. 新增一个结束节点,并命名为“收到付款”

配置“刷卡付款”节点

服务类型有很多执行的方法,这次我们使用“external(外部)”任务模式

  1. 点击“取信用卡”节点,在右侧的面板中修改Implementation(实现)为 External ,修改Topic为 charge-card

配置流程参数

  1. 点击画布的空白处,右侧的面板会显示当前流程本身的参数

这里我们修改id为payment-retrieval,id是区分流程的标识

然后修改Name 为“付款流程”

最后确保 Executable 是勾选的,只有Executable被勾选,流程才能执行

  1. 点击 File > Save File As.. 或者直接点击工具栏中的保存按钮,将流程保存到你喜欢的位置,命名为 payment.bpmn
到此第一部分结束,如果想直接获取到现在为止的进度,可以使用如下命令
git checkout -f Step-1

3.用java或NodeJS实现外部任务

在完成上面流程的编辑后,现在实现“刷卡付款”的业务逻辑

Camunda 可以使多种语言实现业务逻辑,本文将演示java和nodejs两种方式,你可以任意选择喜欢的一种

a)使用JAVA

需要JAVA1.8+,maven(有的IDE自带),IDE

使用喜欢的ide创建一个maven项目,添加maven依赖如下

<dependencies>
        <dependency>
            <groupId>org.camunda.bpm</groupId>
            <artifactId>camunda-external-task-client</artifactId>
            <version>7.15.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
    </dependencies>

编写主类,代码如下

import java.util.logging.Logger;
import java.awt.Desktop;
import java.net.URI;

import org.camunda.bpm.client.ExternalTaskClient;

public class ChargeCardWorker {
  private final static Logger LOGGER = Logger.getLogger(ChargeCardWorker.class.getName());

  public static void main(String[] args) {
    ExternalTaskClient client = ExternalTaskClient.create()
        .baseUrl("http://localhost:8080/engine-rest")
        .asyncResponseTimeout(10000) // 长轮询超时时间
        .build();

    // 订阅指定的外部任务
    client.subscribe("charge-card")
        .lockDuration(1000) // 默认锁定时间为20秒,这里修改为1秒
        .handler((externalTask, externalTaskService) -> {
          // 将您的业务逻辑写在这

          // 获取流程变量
          String item = (String) externalTask.getVariable("item");
          Long amount = (Long) externalTask.getVariable("amount");

          LOGGER.info("Charging credit card with an amount of '" + amount + "'€ for the item '" + item + "'...");

          try {
              Desktop.getDesktop().browse(new URI("https://docs.camunda.org/get-started/quick-start/complete"));
          } catch (Exception e) {
              e.printStackTrace();
          }

          // 完成任务
          externalTaskService.complete(externalTask);
        })
        .open();
  }
}

使用ide上的运行编译运行按钮运行

如果正常运行,则可以进入下一章了

到此第二部分结束,如果想直接获取到现在为止的进度,可以使用如下命令
git checkout -f Step-2a

b)使用NodeJS

需要NodeJS >= v10

首先创建一个新的NodeJS项目

mkdir charge-card-worker
cd ./charge-card-worker
npm init -y

添加Camunda外部任务依赖

npm install camunda-external-task-client-js
npm install -D open

新建一个 JavaScript 文件,命名为 worker.js,代码如下

const { Client, logger } = require('camunda-external-task-client-js');
const open = require('open');

// 外部任务客户端的配置:
//  - 'baseUrl': 流程引擎的url
//  - 'logger': 自动记录的日志等级
//  - 'asyncResponseTimeout': 长轮询的超时时间
const config = { baseUrl: 'http://localhost:8080/engine-rest', use: logger, asyncResponseTimeout: 10000 };

// 根据配置创建一个新的外部任务客户端
const client = new Client(config);

// 订阅charge-card
client.subscribe('charge-card', async function({ task, taskService }) {
  // 将您的业务逻辑写在这

  // 获取流程变量
  const amount = task.variables.get('amount');
  const item = task.variables.get('item');

  console.log(`Charging credit card with an amount of ${amount}€ for the item '${item}'...`);

  open('https://docs.camunda.org/get-started/quick-start/success');

  // 完成任务
  await taskService.complete(task);
});

运行

node ./worker.js

如果正常运行,则可以进入下一章了

到此第二部分结束,如果想直接获取到现在为止的进度,可以使用如下命令
git checkout -f Step-2b

4.部署流程

下面我们将部署流程到流程引擎,然后发起流程,检查流程是否发起成功

使用 Camunda Modeler 部署流程

点击工具栏中的部署按钮可以将当前流程部署到流程引擎,点击部署按钮,输入Deployment Name 为 “Payment” ,输入下方REST Endpoint 为http://localhost:8080/engine-rest ,然后点击右下角Deploy部署

如果收到成功提示,表示部署成功

关于部署的更多内容可以查看  https://blog.camunda.com/post/2019/01/camunda-modeler-3.0.0-0-released/#completely-reworked-deployment-tool

使用Cockpit查看部署结果

在浏览器中打开 http://localhost:8080/camunda/app/cockpit/default/#/processes 使用账号 demo / demo 登录 ,可以看到刚部署的流程显示出来了

创建流程实例(发起流程)

这里使用Rest API发起流程,所以需要一个接口测试工具(例如:Postman),或者也可以使用电脑自带的curl

a) curl

在命令行中执行

curl -H "Content-Type: application/json" -X POST -d '{"variables": {"amount": {"value":555,"type":"long"}, "item": {"value":"item-xyz"} } }' http://localhost:8080/engine-rest/process-definition/key/payment-retrieval/start

如果能看到成功的返回结果,则流程发起成功

b)Postman

在url中输入 http://localhost:8080/engine-rest/process-definition/key/payment-retrieval/start

模式选择POST

点击Body,选择raw,并在右面选择application/json

然后输入Body内容:

{
    "variables": {
        "amount": {
            "value":555,
            "type":"long"
        },
        "item": {
            "value": "item-xyz"
        }
    }
}

编辑完成后,结果这样:

点击 Send 发送请求 

如果能看到成功的返回结果,则流程发起成功

 

import org.camunda.bpm.engine.RuntimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/payment")
public class PaymentController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private PaymentRepository paymentRepository; // 注入支付存储库

    @PostMapping("/start")
    public String startPaymentProcess(@RequestBody PaymentRequest paymentRequest) {
        // 创建并保存付款记录
        Payment payment = new Payment();
        payment.setAmount(paymentRequest.getAmount());
        paymentRepository.save(payment); // 将支付记录保存到数据库

        // 启动流程实例并传递参数
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
            "payment-retrieval", 
            Variables.putValue("amount", paymentRequest.getAmount())
        );

        return "Process started with ID: " + processInstance.getId();
    }
}

编写service层的bmp逻辑 

import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.variable.Variables;

public class ProcessStarter {

    private RuntimeService runtimeService;

    public ProcessStarter(RuntimeService runtimeService) {
        this.runtimeService = runtimeService;
    }

    public String startProcess(String processKey, int amount) {
        // 创建流程变量
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
                processKey,
                Variables.putValue("amount", amount) // 传递参数
        );

        return processInstance.getId(); // 返回流程实例ID
    }
}

编写事务层的逻辑

import org.camunda.bpm.engine.RuntimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PaymentService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private PaymentRepository paymentRepository; // 注入支付存储库

    @Transactional // 在服务层管理事务
    public String startPaymentProcess(PaymentRequest paymentRequest) {
        // 创建并保存付款记录
        Payment payment = new Payment();
        payment.setAmount(paymentRequest.getAmount());
        paymentRepository.save(payment); // 将支付记录保存到数据库

        // 启动流程实例并传递参数
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
            "payment-retrieval", 
            Variables.putValue("amount", paymentRequest.getAmount())
        );

        return processInstance.getId();
    }
}

 

 

 进阶部分Camunda SpringBoot与进阶内容 - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值