1. Overview
1.概述
Flowable is a business process engine written in Java. In this tutorial, we’ll go through the details of business processes and understand how we can leverage the Flowable Java API to create and deploy a sample business process.
Flowable是一个用Java编写的业务流程引擎。在本教程中,我们将了解业务流程的细节,并理解我们如何利用Flowable Java API来创建和部署一个示例业务流程。
2. Understanding Business Processes
2.了解业务流程
Simply put, a Business Process is a set of tasks that, once completed in a defined order, accomplishes a defined objective. Each task in a Business Process has clearly defined inputs and outputs. These tasks may require human intervention or may be completely automated.
简单地说,一个业务流程是一组任务,一旦按照规定的顺序完成,就能完成一个规定的目标。业务流程中的每个任务都有明确定义的输入和输出。这些任务可能需要人工干预,也可能完全自动化。
OMG (Object Management Group) has defined a standard called Business Process Model and Notation (BPMN) for businesses to define and communicate their processes. BPMN has come to be widely supported and accepted in the industry. The Flowable API fully supports creating and deploying BPMN 2.0 process definitions.
OMG(Object Management Group)定义了一个名为Business Process Model and Notation(BPMN)的标准,用于企业定义和沟通他们的流程。BPMN已被业界广泛支持和接受。Flowable API完全支持创建和部署BPMN 2.0流程定义。
3. Creating Process Definitions
3.创建流程定义
Let’s suppose we have a simple process for article review before publishing.
让我们假设我们有一个简单的文章发表前的审查过程。
The gist of this process is that authors submit an article, and editors either accept or reject it. If accepted, the article is published immediately; however, if rejected, the author is notified through email:
这个过程的要点是,作者提交文章,编辑要么接受要么拒绝。如果被接受,文章就会立即发表;但是,如果被拒绝,就会通过电子邮件通知作者。
We create process definitions as XML files using the BPMN 2.0 XML standard.
我们使用BPMN 2.0 XML标准将流程定义创建为XML文件。
Let’s define our simple process as per the BPMN 2.0 standard:
让我们按照BPMN 2.0标准来定义我们的简单流程。
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="articleReview"
name="A simple process for article review." isExecutable="true">
<startEvent id="start" />
<sequenceFlow sourceRef="start" targetRef="reviewArticle" />
<userTask id="reviewArticle" name="Review the submitted tutorial"
flowable:candidateGroups="editors" />
<sequenceFlow sourceRef="reviewArticle" targetRef="decision" />
<exclusiveGateway id="decision" />
<sequenceFlow sourceRef="decision" targetRef="tutorialApproved">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="tutorialRejected">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${!approved}]]>
</conditionExpression>
</sequenceFlow>
<serviceTask id="tutorialApproved" name="Publish the approved tutorial."
flowable:class="com.baeldung.service.PublishArticleService" />
<sequenceFlow sourceRef="tutorialApproved" targetRef="end" />
<serviceTask id="tutorialRejected" name="Send out rejection email"
flowable:class="com.baeldung.service.SendMailService" />
<sequenceFlow sourceRef="tutorialRejected" targetRef="end" />
<endEvent id="end" />
</process>
</definitions>
Now, there are quite a number of elements here that are standard XML stuff, while others are specific to BPMN 2.0:
现在,这里有相当多的元素是标准的XML东西,而其他元素是BPMN 2.0特有的。
- The entire process is wrapped in a tag called “process”, which in turn, is part of a tag called “definitions”
- A process consists of events, flows, tasks, and gateways
- An event is either a start event or an end event
- A flow (in this example, a sequence flow) connects other elements like events and tasks
- Tasks are where actual work is done; these can be “user tasks” or “service tasks”, among others
- A user task requires a human user to interact with the Flowable API and take action
- A service task represents an automatic task, which can be a call to a Java class or even an HTTP call
- A gateway executes based on the attribute “approved”; this is known as a process variable, and we’ll see how to set them later
While we can create process definition files in any text editor, this isn’t always the most convenient way. Fortunately, though, Flowable also comes with user interface options to do this using either an Eclipse plugin or a Web Application. If you’re using IntelliJ instead, there’s an IntelliJ plugin available as well.
虽然我们可以在任何文本编辑器中创建流程定义文件,但这并不总是最方便的方法。不过幸运的是,Flowable 也提供了用户界面选项,可以使用Eclipse 插件或Web 应用程序来完成这一工作。如果您使用 IntelliJ,也有一个IntelliJ 插件可供选择。
4. Working with Flowable API
4.使用可流动的API工作
Now that we’ve defined our simple process in an XML file as per the BPMN 2.0 standard, we need a way to submit and run it. Flowable provides the Process Engine API to interact with Flowable Engines. Flowable is very flexible and offers several ways to deploy this API.
现在我们已经按照BPMN 2.0标准在一个XML文件中定义了我们的简单流程,我们需要一种方法来提交和运行它。Flowable提供了用于与Flowable引擎交互的流程引擎API。Flowable非常灵活,提供了几种部署该API的方法。
Given that Flowable is a Java API, we can include the process engine in any Java application by simply including the requisite JAR files. We can very well leverage Maven for managing these dependencies.
鉴于Flowable是一个Java API,我们可以在任何Java应用程序中包含流程引擎,只需包含必要的JAR文件。我们可以很好地利用Maven来管理这些依赖关系。
Moreover, Flowable comes with bundled APIs to interact with Flowable over HTTP. We can use these APIs to pretty much do anything otherwise possible through Flowable API.
此外,Flowable还捆绑了API,通过HTTP与Flowable进行交互。我们可以使用这些API来做任何通过Flowable API可以做到的事情。
Finally, Flowable has excellent support for integration with Spring and Spring Boot! We’ll make use of Flowable and Spring Boot integration in our tutorial.
最后,Flowable对与Spring和Spring Boot的集成有很好的支持!我们将在教程中利用Flowable和Spring Boot的集成。
5. Creating a Demo Application with Process Engine
5.用Process Engine创建一个演示应用程序
Let’s now create a simple application that wraps a process engine from Flowable and offers an HTTP-based API to interact with the Flowable API. There may as well be a web or mobile application sitting on top of the API to make the experience better, but we’ll skip for that for this tutorial.
现在让我们创建一个简单的应用程序,它包裹了一个来自Flowable的流程引擎,并提供一个基于HTTP的API来与Flowable API交互。为了使体验更好,也可以在API之上建立一个Web或移动应用程序,但在本教程中我们将跳过这一点。
We’ll create our demo as a Spring Boot application.
我们将把我们的演示创建为一个Spring Boot应用程序。
5.1. Dependencies
依赖性
First, let’s see the dependencies we need to pull from Maven:
首先,让我们看看我们需要从Maven中提取的依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.4.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
The dependencies we require are all available at Maven Central:
我们需要的依赖项都可以在Maven中心找到。
- Spring Boot Starter for Web — this is a standard starter for Spring Boot
- Flowable Starter for Spring Boot — this is required for Spring Boot Flowable Engines
- H2 Database — Flowable requires a database to store data, and H2 is the default in-memory database
5.2. Process Definition
5.2.过程定义
When we start our Spring Boot application, it tries to automatically load all process definitions present under the folder “resources/processes”. Therefore, let’s create an XML file with the process definition we created above, with the name “article-workflow.bpmn20.xml”, and place it in that folder.
当我们启动Spring Boot应用程序时,它会尝试自动加载 “resources/processes “文件夹下的所有流程定义。因此,让我们用上面创建的流程定义创建一个XML文件,名称为 “article-workflow.bpmn20.xml”,并将其放在该文件夹中。
5.3. Configurations
5.3.配置
As we’re aware that Spring Boot takes a highly opinionated approach towards application configuration, that goes true for Flowable as part of Spring Boot as well. For instance, detecting H2 as the only database driver on the classpath, Flowable automatically configures it for use.
我们知道,Spring Boot对应用程序的配置采取了一种非常有主见的方法,这对于作为Spring Boot一部分的Flowable来说也是如此。例如,检测到H2是classpath上唯一的数据库驱动程序,Flowable会自动配置它的使用。
Obviously, every aspect that is configurable can be configured in a custom manner through application properties. For this tutorial, however, we’ll stick to the defaults!
显然,可配置的每个方面都可以通过应用程序属性以自定义方式进行配置。然而,在本教程中,我们将坚持使用默认值
5.4. Java Delegates
5.4.Java委托人
In our process definition, we’ve used a couple of Java classes that are supposed to be invoked as parts of service tasks. These classes implement the JavaDelegate interface and are known as Java Delegates in Flowable. We’ll now define dummy classes for these Java Delegates:
在我们的流程定义中,我们使用了几个Java类,它们应该作为服务任务的一部分被调用。这些类实现了JavaDelegate接口,在Flowable中被称为Java Delegates。我们现在将为这些Java Delegates定义虚拟类。
public class PublishArticleService implements JavaDelegate {
public void execute(DelegateExecution execution) {
System.out.println("Publishing the approved article.");
}
}
public class SendMailService implements JavaDelegate {
public void execute(DelegateExecution execution) {
System.out.println("Sending rejection mail to author.");
}
}
Obviously, we must replace these dummy classes with actual services to publish an article or send an email.
很明显,我们必须用实际的服务来取代这些假的类,以发表文章或发送电子邮件。
5.5. HTTP APIs
5.5.HTTP APIs
Finally, let’s create some endpoints to interact with the process engine and work with the process we’ve defined.
最后,让我们创建一些端点,与流程引擎互动,并与我们定义的流程一起工作。
We’ll begin by defining a controller exposing three endpoints:
我们将首先定义一个控制器,暴露三个端点。
@RestController
public class ArticleWorkflowController {
@Autowired
private ArticleWorkflowService service;
@PostMapping("/submit")
public void submit(@RequestBody Article article) {
service.startProcess(article);
}
@GetMapping("/tasks")
public List<Article> getTasks(@RequestParam String assignee) {
return service.getTasks(assignee);
}
@PostMapping("/review")
public void review(@RequestBody Approval approval) {
service.submitReview(approval);
}
}
Our controller exposes endpoints to submit an article for review, fetch a list of articles to review, and finally, to submit a review for an article. Article and Approval are standard POJOs that can be found in the repository.
我们的控制器暴露了一些端点,用来提交一篇文章供审查,获取一个要审查的文章列表,最后,提交一篇文章的审查。Article和Approval是标准的POJOs,可以在资源库中找到。
We are actually delegating most of the work to ArticleWorkflowService:
我们实际上是将大部分工作委托给ArticleWorkflowService:。
@Service
public class ArticleWorkflowService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Transactional
public void startProcess(Article article) {
Map<String, Object> variables = new HashMap<>();
variables.put("author", article.getAuthor());
variables.put("url", article.getUrl());
runtimeService.startProcessInstanceByKey("articleReview", variables);
}
@Transactional
public List<Article> getTasks(String assignee) {
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateGroup(assignee)
.list();
return tasks.stream()
.map(task -> {
Map<String, Object> variables = taskService.getVariables(task.getId());
return new Article(task.getId(), (String) variables.get("author"), (String) variables.get("url"));
})
.collect(Collectors.toList());
}
@Transactional
public void submitReview(Approval approval) {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("approved", approval.isStatus());
taskService.complete(approval.getId(), variables);
}
}
Now, most of the code here is pretty intuitive, but let’s understand the salient points:
现在,这里的大部分代码是非常直观的,但让我们了解一下突出的要点。
- RuntimeService to instantiate the process for a particular submission
- TaskService to query and update tasks
- Wrapping all database calls in transactions supported by Spring
- Storing details like author and URL, among others, in a Map, and saving with the process instance; these are known as process variables, and we can access them within a process definition, as we saw earlier
Now, we’re ready to test our application and process engine. Once we start the application, we can simply use curl or any REST client like Postman to interact with the endpoints we’ve created.
现在,我们已经准备好测试我们的应用程序和流程引擎了。一旦我们启动应用程序,我们可以简单地使用curl或任何REST客户端,如Postman,与我们所创建的端点进行交互。
6. Unit Testing Processes
6.单元测试过程
Flowable supports different versions of JUnit, including JUnit 5, for creating unit tests for business processes. Flowable integration with Spring has suitable support for this as well. Let’s see a typical unit test for a process in Spring:
Flowable支持不同版本的JUnit,包括JUnit 5,用于创建业务流程的单元测试。Flowable与Spring的集成对此也有合适的支持。让我们看看Spring中一个典型的流程的单元测试。
@ExtendWith(FlowableSpringExtension.class)
@ExtendWith(SpringExtension.class)
public class ArticleWorkflowUnitTest {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Test
@Deployment(resources = { "processes/article-workflow.bpmn20.xml" })
void articleApprovalTest() {
Map<String, Object> variables = new HashMap<>();
variables.put("author", "test@baeldung.com");
variables.put("url", "http://baeldung.com/dummy");
runtimeService.startProcessInstanceByKey("articleReview", variables);
Task task = taskService.createTaskQuery().singleResult();
assertEquals("Review the submitted tutorial", task.getName());
variables.put("approved", true);
taskService.complete(task.getId(), variables);
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
}
}
This should pretty much look like a standard unit test in Spring, except for few annotations like @Deployment. Now, the @Deployment annotation is provided by Flowable to create and delete a process deployment around test methods.
除了@Deployment等少数注解外,这应该和Spring中的标准单元测试差不多了。现在,@Deployment注解是由Flowable提供的,用于创建和删除测试方法周围的流程部署。
7. Understanding the Deployment of Processes
7.了解流程的部署
While we’ll not cover the details of process deployment in this tutorial, it is worthwhile to cover some aspects that are of importance.
虽然我们不会在本教程中介绍流程部署的细节,但值得介绍的是一些重要的方面。
Typically, processes are archived as Business Archive (BAR) and deployed in an application. While being deployed, this archive is scanned for artifacts — like process definitions — and processed. You may have noticed the convention of the process definition file ending with “.bpmn20.xml”.
通常,流程被归档为业务归档(BAR),并在应用程序中部署。在部署时,该归档文件被扫描为工件–如流程定义–并被处理。你可能已经注意到流程定义文件以“.bpmn20.xml “结束的惯例。
While we’ve used the default in-memory H2 database in our tutorial, this actually cannot be used in a real-world application, for the simple reason that an in-memory database will not retain any data across start-ups and is practically impossible to use in a clustered environment! Hence, we must use a production-grade relational database and provide the required configurations in the application.
虽然我们在教程中使用了默认的内存H2数据库,但这实际上不能用于现实世界的应用,原因很简单,内存数据库不会在启动时保留任何数据,而且实际上不可能在集群环境中使用!因此,我们必须使用生产级的关系数据库,并在应用程序中提供所需的配置。因此,我们必须使用生产级的关系型数据库,并在应用程序中提供所需的配置。
While BPMN 2.0 itself does not have any notion of versioning, Flowable creates a version attribute for the process, which is deployed in the database. If an updated version of the same process, as identified by the attribute “id”, is deployed, a new entry is created with the version being incremented. When we try to start a process by “id”, the process engine fetches the latest version of the process definition deployed.
虽然BPMN 2.0本身没有任何版本的概念,但Flowable为流程创建了一个版本属性,它被部署在数据库中。如果同一流程的更新版本(由属性 “id “识别)被部署,就会创建一个新的条目,其版本会被递增。当我们试图通过 “id “启动一个流程时,流程引擎会获取所部署的流程定义的最新版本。
If we use one of the designers we discussed earlier to create the process definition, we already have a visualization for our process. We can export the process diagram as an image and place it alongside the XML process definition file. If we stick to the standard naming convention suggested by Flowable, this image will be processed by the process engine along with the process itself. Moreover, we can fetch this image through APIs as well!
如果我们使用我们先前讨论的设计器之一来创建流程定义,我们已经有了流程的可视化。我们可以将流程图导出为图像,并将其放在 XML 流程定义文件的旁边。如果我们坚持 Flowable 建议的标准 命名惯例,该图像将与流程本身一起被流程引擎处理。此外,我们也可以通过API来获取这个图像
8. Browsing History of Process Instances
8.浏览进程实例的历史
It is often of key importance in the case of business processes to understand what happened in the past. We may need this for simple debugging or complex legal auditing purposes.
在业务流程中,了解过去发生的事情往往具有关键的重要性。我们可能需要这个来进行简单的调试或复杂的法律审计目的。
Flowable records what happens through the process execution and keeps it in the database. Moreover, Flowable makes this history available through APIs to query and analyze. There are six entities under which Flowable records these, and the HistoryService has methods to query them all.
Flowable记录了流程执行过程中发生的事情,并将其保存在数据库中。此外,Flowable通过API使这些历史记录可用来查询和分析。有六个实体,Flowable在这些实体下进行记录,而HistoryService有方法来查询它们。
Let’s see a simple query to fetch finished process instances:
让我们看看一个简单的查询来获取已完成的进程实例。
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> activities = historyService
.createHistoricActivityInstanceQuery()
.processInstanceId(processInstance.getId())
.finished()
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
As we can see, the API to query recorded data is pretty composable. In this example, we’re querying finished process instances by ID and ordering them in ascending order of their end time.
正如我们所看到的,查询记录数据的API是相当可组合的。在这个例子中,我们通过ID来查询已完成的进程实例,并按照结束时间的升序来排列它们。
9. Monitoring Processes
9.监测过程
Monitoring is a key aspect of any business-critical application, and even more so for an application handling business processes of an organization. Flowable has several options to let us monitor processes in real time.
监控是任何业务关键型应用程序的一个关键方面,对于处理组织业务流程的应用程序更是如此。Flowable有几个选项可以让我们实时监控流程。
Flowable provides specific MBeans that we can access over JMX, to not only gather data for monitoring but to perform many other activities as well. We can integrate this with any standard JMX client, including jconsole, which is present alongside standard Java distributions.
Flowable提供了特定的MBeans,我们可以通过JMX访问它,不仅可以收集数据用于监控,还可以执行许多其他活动。我们可以将其与任何标准的JMX客户端集成,包括jconsole,它与标准的Java发行版一起存在。
Using JMX for monitoring opens a lot of options but is relatively complex and time-consuming. However, since we’re using Spring Boot, we’re in luck!
使用JMX进行监控开启了很多选择,但相对复杂和费时。然而,由于我们使用的是Spring Boot,所以我们很幸运!
Spring Boot offers Actuator Endpoints to gather application metrics over HTTP. We can seamlessly integrate this with a tool stack like Prometheus and Grafana to create a production-grade monitoring tool with minimal effort.
Spring Boot 提供 Actuator Endpoints以通过 HTTP 收集应用程序的指标。我们可以将其与Prometheus和Grafana等工具栈无缝集成,以最小的工作量创建一个生产级监控工具。
Flowable provides an additional Actuator Endpoint exposing information about the running processes. This is not as good as gathering information through JMX, but it is quick, easy and, most of all, sufficient.
Flowable提供了一个额外的执行器端点,暴露了关于正在运行的进程的信息。这不如通过JMX收集信息,但它快速、简单,最重要的是,足够了。
10. Conclusion
10.结语
In this tutorial, we discussed business processes and how to define them in the BPMN 2.0 standard. Then, we discussed the capabilities of Flowable process engine and APIs to deploy and execute processes. We saw how to integrate this in a Java application, specifically in Spring Boot.
在本教程中,我们讨论了业务流程以及如何在BPMN 2.0标准中定义它们。然后,我们讨论了Flowable流程引擎的功能以及部署和执行流程的API。我们看到了如何在Java应用程序中集成这些功能,特别是在Spring Boot中。
Continuing further, we discussed other important aspects of processes like their deployment, visualization, and monitoring. Needless to say, we’ve just scratched the surface of the business process and a powerful engine like Flowable. Flowable has a very rich API with sufficient documentation available. This tutorial, however, should have piqued our interest in the subject!
继续深入,我们讨论了流程的其他重要方面,如其部署、可视化和监控。不用说,我们只是触及了业务流程和Flowable这样一个强大引擎的表面。Flowable有一个非常丰富的API,并有足够的文档可用。然而,这个教程应该已经激起了我们对这个主题的兴趣!
As always, the code for the examples is available over on GitHub.
像往常一样,这些例子的代码可以在GitHub上找到over。