camunda流程引擎基本使用(笔记)

news2024/12/27 1:26:51

文章目录

  • 一、camunda基础
    • 1.1 安装与部署流程引擎
    • 1.2 流程引擎结构
    • 1.3 流程引擎的基本使用
      • 1.3.1 创建一个BPMN Diagram
      • 1.3.2 实现一个外部工作者
      • 1.3.3 部署流程
      • 1.3.4 创建一个流程实例并消费
      • 1.3.5 向流程中添加用户任务
      • 1.3.6 添加网关
      • 1.3.7 业务规则
  • 二、Java 集成流程引擎
    • 2.1 为项目引入Platform
      • 2.1.1 页面配置
    • 2.2 简单使用
      • 2.2.1 引入API
      • 2.2.2 服务
      • 2.2.3 部署流程
    • 2.3 流程部署详细介绍
  • 附录

一、camunda基础

Camunda介绍 Camunda是一种工作流引擎,是由Java开发的一个纯Java库。

通常集成在我们的服务中,作为其中一块功能。

1.1 安装与部署流程引擎

官方-下载引导地址

  • Camunda Platform 和 Camunda Modeler是必要的文件。
    • Camunda Platform:这里是流程引擎的用户、租户等部分的管理界面
    • Camunda Modeler:流程引擎的核心,即流程相关的部分

  • docker安装
docker pull camunda/camunda-bpm-platform:run-latest
docker run -d --name camunda -p 8080:8080 camunda/camunda-bpm-platform:run-latest
  • 非docker安装

Camunda Platform 下载地址

我们下载好后,需要到这个路径下。这里是创建表的sql语句,选择自己的数据库运行语句,来创建对应的表。
在这里插入图片描述

修改default.yml 中数据源和JDBC 替换为自己使用的数据库的配置

然后把对应的JDBC放入标注上面的userlib之中即可。

在这里插入图片描述

Camunda Modeler 下载地址
我们在点击运行后可以直接使用。
在这里插入图片描述

1.2 流程引擎结构

在这里插入图片描述

在这里插入图片描述

1.3 流程引擎的基本使用

我们创建在Camunda Modeler中创建一个流程,然后我们可以用Java或者JS,按照流程去执行它。

本篇使用Java处理。

1.3.1 创建一个BPMN Diagram

首先,我们可以创建一个BPMN Diagram。

Business Process Modeling Notation,简称BPMN

它的事件包含

  • 开始(Start)
  • 中间(Intermediate)
  • 边界(Boundary)
  • 结束(End)

根据触发方式不同,可以分为

  • 捕获事件(Catching Event)
  • 抛出事件(Throwing Event)

具体的使用方式请参考:参考-Executing automated steps 、Service tasks

我们准备一个简易的流程,如下图(与官方例子一致)。
这里可以直接下载官方的例子下载避免繁琐的配置操作
在这里插入图片描述
注意一下,最新版的是可集群的版本(版本8)
在这里插入图片描述
我们使用的是如下的版本(版本7)
在这里插入图片描述

1.3.2 实现一个外部工作者

换言之就是创建一个Java程序,用它以处理BPMN Diagram

这里是官方的写的依赖,依据自己的需要改动即可。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>org.camunda.bpm.getstarted</groupId>
	<artifactId>charge-card-worker</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<camunda.external-task-client.version>7.17.0</camunda.external-task-client.version>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.camunda.bpm</groupId>
			<artifactId>camunda-external-task-client</artifactId>
			<version>${camunda.external-task-client.version}</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>
</project>

笔者改为Spring Boot(Java11)

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.6</version>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>

        <dependency>
            <groupId>org.camunda.bpm</groupId>
            <artifactId>camunda-external-task-client</artifactId>
            <version>7.18.0</version>
        </dependency>
    </dependencies>

该程序连接的是 Camunda Platform 系统注意端口和IP。
在这里插入图片描述

import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.client.ExternalTaskClient;

import java.awt.*;
import java.net.URI;



@Slf4j
public class ChargeCardWorker {

  public static void main(String[] args) {
    ExternalTaskClient client = ExternalTaskClient.create()
    // 依据实际情况填写程序的IP和端口
        .baseUrl("http://localhost:8080/engine-rest")
        // 异步相应超时时间
        .asyncResponseTimeout(10000) // long polling timeout
        .build();

    // subscribe to an external task topic as specified in the process
    // 订阅流程中指定的外部任务主题,与活动ID对应
    client.subscribe("charge-card")
    	// 默认锁的持续时间为20秒
        .lockDuration(1000) // the default lock duration is 20 seconds, but you can override this
        // 处理内容
        // externalTask:任务,externalTaskService:处理服务
        .handler((externalTask, externalTaskService) -> {
          // Put your business logic here

          // Get a process variable
          String item = externalTask.getVariable("item");
          Integer amount = externalTask.getVariable("amount");

          log.info("Charging credit card with an amount of '{}'€ for the item '{}'...",amount,item);

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

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

在这里插入图片描述
这里的活动的Topic与我们的工作者一致。因而可以知道活动有对应的工作者去处理。

通过改变活动以及活动的顺序来改变流程,而活动自己被不同的工作者处理后继续流转因而不受影响,以此完成流程。

1.3.3 部署流程

也就是将BPMN Diagram 与 Platform关联,然后让我们的工作者去处理它。
我们将流程部署过去
在这里插入图片描述
成功后,我们进入platform登陆后(默认账号密码均为demo),可以看到流程已经在这里了

http://localhost:8080/camunda/app/cockpit/default/#/processes
在这里插入图片描述
在这里插入图片描述

1.3.4 创建一个流程实例并消费

我们接下来可以使用postman
向这个地址发送Post请求

http://localhost:8080/engine-rest/process-definition/key/payment-retrieval/start

同时在body里面发送如下json参数

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

在这里插入图片描述

当我们在工作者的后台看到如下数据,并且成功打开了一个页面,就说明成功消费了
在这里插入图片描述

在这里插入图片描述
此处的key就是我们process的ID:payment-retrieval

1.3.5 向流程中添加用户任务

当然这里只是最简单的使用。参考-Add a User Task to the Process

依据类似的操作,我们添加一个
在这里插入图片描述
我们把任务分配给demo用户
下面的候选组、人、到期日期请自行参考文档
在这里插入图片描述
我们接着在这个活动的Forms添加如下属性,来向流程中加一个表单
在这里插入图片描述
选择 File > New File > Form(版本7)创建如下表单

并把ID和我们payment-form设置为一样的,来关联起来。
在这里插入图片描述
我们接下来创建一个Amount项目,使用Number类型
在这里插入图片描述
再创建一个文本框,如下设置
在这里插入图片描述
再加一个是否同意
在这里插入图片描述

完成回到流程然后部署,记得加入我们的表单
在这里插入图片描述
来到这个页面,点击框住的按钮

http://localhost:8080/camunda/app/tasklist/

在这里插入图片描述
选择我们创建的流程,开启一个流程

在这里插入图片描述

输入一个业务流程号后,我们可以找到我们的流程以及表格

在这里插入图片描述

同时可以看到流程位置

在这里插入图片描述
填写完成后,我们继续,则会流转到我们前面写的消费者处。

1.3.6 添加网关

也就是类似if-else的方式,来确定流向。

我们先搭出如下内容

网关1

  1. 如果金额小于 1000 就直接处理
  2. 如果大等于 1000 就需要处理

网关2

  1. 判断是否同意
    在这里插入图片描述

我们的判断是加在箭头上的
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
接下来我们部署该流程,按照1.3.5中流程开始一个流程,或者通过PostMan请求,可以看到流程流转到了不同地方。

platform 创建流程
在这里插入图片描述

我们查看,可以看到流程到了这里
在这里插入图片描述
启动我们的外部工作者,即可完成处理。

postman 创建流程
发送的也是和之前一样的请求
在这里插入图片描述

在这里插入图片描述
可以看到我们这里的流程到了1.3.5的部分,在tasklist中我们处理是否同意即可。

1.3.7 业务规则

我们在这里加入业务规则
在这里插入图片描述

在这里插入图片描述

随后我们创建一个新的DMN流程(依然是版本7)。
在这里插入图片描述
我们这里直接把Decision1的ID(决策表)和我们业务规则输入的reference关联起来
在这里插入图片描述

点击框住部分
在这里插入图片描述

创建如下内容

标题我们是Item大写,Expression我们是小写让变量与之后流程一致
在这里插入图片描述
制作如下表格
在这里插入图片描述
到现在为止,我们完成了决策表的制作。

  • 如果我们的item是"item-xyz"决策就是赞成
  • 若果不是,则结果就是不赞成

关于决策表,可以参考Camunda DMN

我们接下来把它部署即可,名字可以取框住的
在这里插入图片描述
随后我们可以在决策里面找到
在这里插入图片描述

在重新部署我们的流程

在这里插入图片描述
然后我们开始流程

在这里插入图片描述
在这里插入图片描述

二、Java 集成流程引擎

我们用SpringBoot集成流程引擎。

可以参考-Camunda-Spring Boot 集成

相关的SpringBoot配置可以参考-流程引擎配置

2.1 为项目引入Platform

<properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <camunda.spring-boot.version>7.18.0</camunda.spring-boot.version>
        <spring-boot.version>2.7.3</spring-boot.version>
        <xml-bind.version>2.3.6</xml-bind.version>
        <maven.compiler.target>11</maven.compiler.target>
        <mybatis-plus.version>3.5.1</mybatis-plus.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

yml

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://IP:Port/DataBase?useUnicode=true&NamePatternMatchesAll=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false
    username: username
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name:   applicationName
camunda:
  bpm:
    admin-user:
      id: demo
      password: demo
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
package camunda;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CamundaApplication {
    public static  void main(String[] args){
        SpringApplication.run(CamundaApplication.class,args);
    }
}

在数据库中我们可以看到我们配置的默认用户。
在这里插入图片描述

启动后我们访问

http://localhost:8080/camunda/app/welcome/default/#!/login

出现如下页面就说明成功了。
在这里插入图片描述
页面和地址的使用方式和我们之前的使用方式是一致的。

2.1.1 页面配置

有页面是因为我们引入了,不需要页面的时候,我们可以不引入它即可。

<dependency>
  <groupId>org.camunda.bpm.springboot</groupId>
  <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
  <version>${camunda.spring-boot.version}</version>
</dependency>

此外,我们可以配置yml,来修改路径以及是否重定向到默认的index.html.

camunda:
  bpm:
    webapp:
      application-path: 路径
      index-redirect-enabled: false

2.2 简单使用

2.2.1 引入API

可以参考-Camunda BPM Javadocs 7.9.19-ee

要使用类似于我们之前用的API,我们可以引入如下依赖:

<dependency>
  <groupId>org.camunda.bpm.springboot</groupId>
  <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
  <version>${camunda.spring-boot.version}</version>
</dependency>

默认API地址为

http://localhost:8080/engine-rest

Camunda使用的是jersey,因而一些配置需要jersey配置方式。

也可以通过修改spring boot的通用应用程序属性来改变API访问地址:

spring:
  jersey:
    application-path=地址

为了修改配置或注册额外的资源,可以提供一个集成自如下的配置类:

org.camunda.bpm.spring.boot.starter.rest.CamundaJerseyResourceConfig 
@Component
@ApplicationPath("/engine-rest")
public class JerseyConfig extends CamundaJerseyResourceConfig {
  @Override
  protected void registerAdditionalResources() {
    register(...);
  }
}

中心起点是ProcessEngine(流程引擎),可以通过配置部分中描述的几种方式创建ProcessEngine。

从ProcessEngine中,可以获得包含 工作流/BPM 方法的各种服务。

ProcessEngine和服务对象是 线程安全 的。所以可以为整个服务器保留对其中一个的引用。
在这里插入图片描述
actiti.cfg.xml文件:

  • 对于所有的actiti.cfg.xml文件,流程引擎将以Spring方式构建:首先创建Spring应用程序上下文,然后从该应用程序上下文获得流程引擎。
  • 如何书写,可参考-activiti配置文件activiti.cfg.xml

服务都是无状态的:

  • 可以在集群中的多个节点上运行Camunda BPM,每个节点都访问同一个数据库,而不必担心哪台机器实际执行了前面的调用。对任何服务的任何调用都是幂等的,无论它在哪里执行。

2.2.2 服务

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

将在第一次调用流程引擎时初始化并构建流程引擎,之后总是返回相同的流程引擎.
可以使用ProcessEngines.init()和ProcessEngines.destroy()来正确地创建和关闭所有的流程引擎


RepositoryService repositoryService = processEngine.getRepositoryService();

RepositoryService可能是使用Camunda引擎时需要的第一个服务。此服务提供用于管理和操作部署和流程定义的操作。

部署 部署内容 意味着将其上传到引擎,在将所有进程存储到数据库之前,都将会对其进行检查和解析。

完成后,系统就知道部署了,之后就可以启动部署中包含的任何进程。

通过该服务,可以:

  • 查询引擎已知的部署和流程定义。
  • 挂起并激活流程定义。挂起意味着不能对它们进行进一步的操作,而激活则是相反的操作。
  • 检索引擎自动生成的部署图或流程图中包含的文件等各种资源

RuntimeService runtimeService = processEngine.getRuntimeService();

RuntimeService处理启动流程定义的新流程实例。

流程定义定义了流程中不同步骤的结构和行为,流程实例是此类流程定义的一次执行。对于每个流程定义,通常都有多个实例同时运行。

RuntimeService也是用于检索和存储流程变量的服务。这是特定于给定流程实例的数据,可以由流程中的各种构造使用(例如,独占网关通常使用流程变量来确定选择哪条路径来继续流程)。

RuntimeService还允许对流程实例和执行进行查询。基本上,执行就是指向流程实例当前位置的指针。

最后,当流程实例等待外部触发器且流程需要继续时,将使用RuntimeService。流程实例可以有各种等待状态,该服务包含各种“通知”实例接收到外部触发器并可以继续该流程实例的操作。


TaskService taskService = processEngine.getTaskService();

需要展示给实际用户执行的任务是流程引擎的核心。

围绕任务的所有内容都分组在TaskService中,例如

  • 查询已分配给用户/组的任务。
  • 创建新的独立任务。这些任务与流程实例无关。
  • 操作将任务分配给哪个用户,或者哪些用户以某种方式参与了任务。
  • 申请并完成一项任务。声明意味着某人决定成为任务的受让人,这意味着该用户将完成任务。完成的意思是“完成任务的工作”。这通常是填写某种表单。

IdentityService identityService = processEngine.getIdentityService();

IdentityService允许对组和用户进行管理(创建、更新、删除、查询等)。

但是,核心引擎在运行时实际上不会对用户进行任何检查。


FormService formService = processEngine.getFormService();

FormService是一个可选服务。

此服务引入了启动表单和任务表单的概念。

  • 启动表单是在流程实例启动之前向用户显示的表单
  • 任务表单是在用户希望完成表单时显示的表单

该服务以一种易于使用的方式公开此数据。但同样,这是可选的,因为表单不需要嵌入到流程定义中。


HistoryService historyService = processEngine.getHistoryService();

HistoryService公开引擎收集的所有历史数据。

在执行流程时,引擎可以保存大量数据(这是可配置的),例如流程实例的开始时间、谁执行了哪些任务、完成任务所需的时间、每个流程实例遵循的路径等等。

该服务主要提供访问此数据的查询功能。


ManagementService managementService = processEngine.getManagementService();

在编写自定义应用程序时,通常不需要ManagementService。

它允许检索关于数据库表和表元数据的信息。此外,它还公开了作业的查询功能和管理操作。作业在引擎中用于各种用途,如计时器、异步延续、延迟挂起/激活等。稍后,我们将更详细地讨论这些主题。


FilterService filterService = processEngine.getFilterService();

FilterService允许创建和管理过滤器。过滤器是像任务查询一样存储的查询。

例如,Tasklist使用过滤器来过滤用户任务。

camunda-Filters


ExternalTaskService externalTaskService = processEngine.getExternalTaskService();

ExternalTaskService提供对外部任务实例的访问。外部任务表示在外部独立于流程引擎处理的工作项。


CaseService caseService = processEngine.getCaseService();

CaseService类似于RuntimeService,但用于案例实例。它处理启动用例定义的新用例实例和管理用例执行的生命周期。该服务还用于检索和更新案例实例的流程变量。


DecisionService decisionService = processEngine.getDecisionService();

DecisionService允许评估部署到引擎的决策。它是在独立于流程定义的业务规则任务中评估决策的一种替代方法。

2.2.3 部署流程

我们在启动类上添加@EnableProcessApplication注释,并将空的processes.xml文件放在src/main/resources/META-INF文件夹中。
在这里插入图片描述

@SpringBootApplication
@EnableProcessApplication
public class CamundaApplication {
    public static  void main(String[] args){
        SpringApplication.run(CamundaApplication.class,args);
    }
}

Camunda Engine的每个流程应用程序都需要该文件,此处我们始终将它保持为空(它会使用默认配置)

这里我们仍然从Modeler处创建一个流程。

在这里插入图片描述
然后保存在如下位置
在这里插入图片描述
启动后,我们可以看到已经成功部署
在这里插入图片描述
在流程定义中可以找到
在这里插入图片描述
此处也可以找到
在这里插入图片描述
如下就是部署与移除的流程,默认的配置下,即使删除bpmn,流程仍然存在于数据库中
在这里插入图片描述

我们可以创一个用于创建实例的类,这里的key就是我们流程的key,至此该监听器监听该流程。
在这里插入图片描述
可以完成部署后立即创建一个实例(重启也会)

@Service
@Slf4j
public class TestCamunda {
    @Autowired
    private RuntimeService runtimeService;

    @EventListener
    private void processPostDeploy(PostDeployEvent event) {
        log.info("{}",event);
        runtimeService.startProcessInstanceByKey("Process_028ntv2");
    }
}

可以在这个位置找到
在这里插入图片描述

我们可以做一个接口,通过接受服务ID,然后用RuntimeService去创建。

消费服务我们之前就写给过了,这里就跳过。

2.3 流程部署详细介绍

默认情况下,camunda-spring-boot-starter 使用SpringProcessEngineConfiguration 配置自动部署功能。

从1.2.0开始,可以通过 SpringBootProcessApplication 配置。这将禁用SpringProcessEngineConfiguration 的自动部署功能。

自动部署功能,用如下路径作为资源扫描的目录。

 META-INF/processes.xml 

允许使用的所有 processes.xml 配置项在这里列出。

在这里插入图片描述
如果是空的,就会用默认配置,如下:

<process-application
  xmlns="http://www.camunda.org/schema/1.0/ProcessApplication"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <process-archive>
    <properties>
      <property name="isDeleteUponUndeploy">false</property>
      <property name="isScanForProcessDefinitions">true</property>
    </properties>
  </process-archive>

</process-application>

官方给出的配置样例:

<process-application
        xmlns="http://www.camunda.org/schema/1.0/ProcessApplication"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <process-archive name="loan-approval">
        <process-engine>default</process-engine>
        <properties>
            <property name="isDeleteUponUndeploy">true</property>
            <property name="isScanForProcessDefinitions">true</property>
        </properties>
    </process-archive>

</process-application>

我们在这里声明了一个单个部署(流程存档),流程存档的名称为loan-approval,并部署到名称为default的流程引擎。

  • isDeleteUponUndeploy:此属性控制流程应用程序的取消部署是否需要从数据库中删除流程引擎部署。

    • 默认设置为false。
    • 如果将此属性设置为true,则取消部署流程应用程序将导致从数据库中删除部署(包括流程实例)。
  • isScanForProcessDefinitions:如果此属性设置为true,则会自动扫描流程应用程序的类路径以查找可部署资源。

配置文件的基本设置,可参考-The processes.xml Deployment Descriptor

配置参数可查阅

  • Process Engine Configuration
  • Process Archive Configuration

只需要添加@EnableProcessApplication注解到SpringBootapplication类即可:


@SpringBootApplication
@EnableProcessApplication
public class CamundaApplication{

}

由于使用@EnableProcessApplication时,没有扩展ProcessApplication类,所以我们不能使用@PostDeploy和@PreUndeploy方法注释。

相反,这些回调是通过Spring事件发布机制提供的。所以可以使用以下事件监听器。


@SpringBootApplication
@EnableProcessApplication
public class CamundaApplication{
	//...
}

@EventListener
public void onPostDeploy(PostDeployEvent event) {
  //...
}

@EventListener
public void onPreUndeploy(PreUndeployEvent event) {
  //...
}

通过监听器,我们可以完成如下操作。
在这里插入图片描述

附录

camunda中文-官方文档
camunda内部构造
camunda英文-官方文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/401563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

酷开科技大数据揭秘!酷开系统中的千屏千面究竟指的是什么?

互联网行业的快速发展&#xff0c;给我们带来了极大的便利。回顾整个互联网行业的发展历程&#xff0c;从PC时代到移动互联网时代&#xff0c;从移动互联网时代到物联网时代&#xff0c;现在又即将从物联网时代迈入人工智能时代。这些飞速发展的背后&#xff0c;其实是对数据利…

ICG-alkyne,吲哚菁绿-炔基结构式,实验室科研试剂,CAS号:1622335-41-4

ICG-alkyne,吲哚菁绿-炔基 中文名称&#xff1a;吲哚菁绿-炔基 CAS号&#xff1a;1622335-41-4 英文名称&#xff1a;ICG-alkyne 英文别名&#xff1a;ICG-alk 性状&#xff1a;绿色粉末 化学式&#xff1a;C48H53N3O4S 分子量&#xff1a;768.03 溶剂&#xff1a;溶于…

3BHE029110R0111 ABB

3BHE029110R0111 ABB变频器控制方式低压通用变频输出电压为380&#xff5e;650V&#xff0c;输出功率为0.75&#xff5e;400kW&#xff0c;工作频率为0&#xff5e;400Hz&#xff0c;它的主电路都采用交—直—交电路。其控制方式经历了以下四代。1U/fC的正弦脉宽调制&#xff0…

ggplot2的组图拓展包(1):patchwork(中篇)

专注系列化、高质量的R语言教程推文索引 | 联系小编 | 付费合集上篇和上篇续介绍了使用操作符进行组图的方法&#xff0c;这里默认读者已经能够理解各种操作符在本篇推文中的使用场景。本篇目录如下&#xff1a;0 示例图形6 plot_layout函数&#xff08;下&#xff09;6.1 guid…

CSS3-数据可视化

2D动画 - transform CSS3 transform属性允许你旋转&#xff0c;缩放&#xff0c;倾斜或平移给定元素。 Transform是形变的意思&#xff08;通常也叫变换&#xff09;&#xff0c;transformer就是变形金刚 常见的函数transform function有&#xff1a; 平移&#xff1a;transl…

实际开发中如何存储密码(md5加盐bcrypt)golang

文章目录简介加盐的加密方式md5 加盐方式bcrypt 方式简介 一般前端把用户密码发给服务端&#xff0c;服务端实际业务中如何存储密码呢&#xff0c;如何存储密码才能保证密码不被开发者获取或者被截取呢&#xff0c;保证密码的安全 加盐的加密方式 现在的企业开发大都采用这种…

凌恩生物文献分享|颠覆性的宏基因组新思路,速来get!

非人灵长类动物&#xff08;NHP&#xff09;是人类的近亲&#xff0c;为宿主-微生物互作的研究提供了一个很好的例子。近年来研究主要集中在野生灵长类动物的肠道微生物群&#xff0c;这将有助于了解灵长类及其肠道微生物群的进化&#xff0c;但仍然缺乏关于野生种群肠道微生物…

通用后台管理系统-前端搭建

一 背景 基于vuespringboot 搭建一套通用管理后台 主要包括用户管理模块、权限模块、菜单模块 二 环境信息 2.1 前端工具版本 2.1.1 npm 版本 PS D:\front> npm -v 8.5.0PS D:\front> npm config get registry https://registry.npm.taobao.org/ PS D:\front>2.1…

埋点tracker:前端埋点服务-技术要点梳理

一、背景埋点方案&#xff0c;前端涉及到哪些技术要点&#xff0c;本文做简单的梳理和总结。二、指纹追踪技术&#xff1a;识别到用户及设备浏览器&#xff1a;浏览器指纹_snowli的博客-CSDN博客三、用户设备信息&#xff08;navigator&#xff09;navigator.userAgent四、页面…

利用Mysql存储过程造百万级数据

1.准备工作&#xff08;1&#xff09;由于是使用存储过程&#xff0c;mysql从5.0版开始支持存储过程&#xff0c;那么需要mysql的版本在5.0或者以上。如何查看mysql的版本&#xff0c;使用下面sql语句查看&#xff1a;&#xff08;2&#xff09;创建两张表&#xff0c;表结构一…

Android Crash和ANR监控

文章目录一、Crash1.1 概念1.2 类型二、ANR2.1 概念2.2 类型2.2.1 KeyDispatchTimeout&#xff08;常见&#xff09;2.2.2 BroadcastTimeout2.2.3 ServiceTimeout2.2.4 ContentProviderTimeout三、测试中如何关注3.1 Crash测试关注方法3.2 ANR测试关注方法四、如何记录与处理4.…

C++复习笔记--STL的string容器和vector容器

1--string容器string 本质上是一个类&#xff0c;其不同于指针 char*&#xff0c;string 类的内部封装了 char*&#xff0c;用于管理字符串&#xff0c;是一个 char* 型的容器&#xff1b;1-1--string构造函数string 的构造函数原型&#xff1a;string(); // 创建一个空的字符串…

媒体邀约的形式和步骤

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 做媒体服务很多年&#xff0c;今天就与大家分享下媒体邀约都有哪些形式&#xff1a; 1&#xff0c;电话邀约&#xff1a;通过电话与媒体记者进行沟通&#xff0c;邀请其参加活动或接受采…

CDC 长沙站丨云原生技术研讨会:数字兴链,云化未来!

一、活动信息&#xff1a;活动主题&#xff1a;CDC 长沙站丨云原生技术研讨会活动时间&#xff1a;2023 年 3 月 14 日下午 14&#xff1a;30-17&#xff1a;30活动地点&#xff1a;长沙市岳麓区-拓维信息总部 1 楼多功能厅活动参与方式&#xff1a;免门票参与&#xff0c;戳此…

船舶自动驾驶避撞规则

1无人船避碰阶段 如图1所示。 第一阶段&#xff1a;感知阶段。使用雷达、AIS、激光雷达和视觉传感器等感知传感器进行障碍物检测。利用感知到的信息&#xff0c;获得障碍物的运动信息。 第二阶段&#xff1a;决策阶段。利用障碍物的运动信息做出避免冲突的决策。在这一阶段&am…

数据结构排序比较

排序的概念及其运用 (1)排序的概念 排序:所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性:假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&am…

Spring-AOP工作流程

Spring-AOP工作流程 3&#xff0c;AOP工作流程 3.1 AOP工作流程 由于AOP是基于Spring容器管理的bean做的增强&#xff0c;所以整个工作过程需要从Spring加载bean说起: 流程1:Spring容器启动 容器启动就需要去加载bean,哪些类需要被加载呢?需要被增强的类&#xff0c;如:B…

C++ Qt自建网页浏览器

C Qt自建网页浏览器如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01;前言这篇博客针对<<C Qt自建网页浏览器>>编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 学习与应用推荐首选。文…

手把手教你实现书上的队列,进来试试?

一.队列的基本概念队列的定义队列&#xff08;queue&#xff09;是只允许在一端进行插入操作&#xff0c;而在另一端进行删除操作的线性表。队列是一种先进先出&#xff08;First In First Out&#xff09;的线性表&#xff0c;简称FIFO。允许插入的一端称为队尾&#xff0c;允…

如何取消电脑开机密码?1分钟可学会,快速取消

​如果小伙伴觉得每次开机都需要输入密码很烦&#xff0c;那么小伙伴应该学会如何取消电脑开机密码。本篇文章&#xff0c;小编将以图文教学的方式&#xff0c;向小伙伴介绍如何在短短的1分钟内&#xff0c;就能够取消电脑开机密码&#xff0c;让小伙伴摆脱烦人的开机密码&…