1. 概述
Flowable 是一個用 Java 編寫的業務流程引擎。在本教程中,我們將深入瞭解業務流程的細節,並學習如何利用 Flowable Java API 創建和部署一個示例業務流程。
2. 瞭解業務流程
簡單來説,業務流程是指在明確的順序中完成的一系列任務,從而實現明確的目標。 每個業務流程中的任務都有明確的輸入和輸出。這些任務可能需要人工干預,也可能完全自動化。
OMG(對象管理組)定義了一種標準,稱為 業務流程建模與表示法(BPMN),供企業定義和溝通其流程。 BPMN 在行業中得到了廣泛的支持和認可。 Flowable API 完整地支持創建和部署 BPMN 2.0 流程定義。
3. 創建流程定義
假設我們有一個簡單的文章發佈前審核流程。
該流程的核心是作者提交文章,編輯者對其進行接受或拒絕。如果接受,文章將立即發佈;如果拒絕,作者將通過電子郵件收到通知:
我們使用 BPMN 2.0 XML 標準創建流程定義,這些流程定義以 XML 文件形式存儲。
讓我們按照 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>現在,這裏有相當多的元素是標準XML內容,而另一些則特定於BPMN 2.0:
- 整個流程被包含在一個名為“process”的標籤中,而該標籤又屬於一個名為“definitions”的標籤內
- 流程由事件、流程、任務和網關組成
- 事件可以是啓動事件或結束事件
- 流程(在本例中,順序流程)連接其他元素,如事件和任務
- 任務是實際工作的地方;這些可以是“用户任務”或“服務任務”等
- 用户任務需要人類用户與Flowable API交互並採取行動
- 服務任務代表自動任務,可以是對Java類的一次調用,甚至是一個HTTP調用
- 網關根據“approved”屬性執行,這被稱為流程變量,我們稍後將看到如何設置它們
雖然我們可以使用任何文本編輯器創建流程定義文件,但這並不總是最方便的方法。 幸運的是,Flowable也提供了用户界面選項,可以使用Eclipse插件或Web應用程序來完成。如果您使用的是IntelliJ,還有一個IntelliJ插件可用。
4. 使用 Flowable API
現在我們已經根據 BPMN 2.0 標準定義了簡單的流程,並將其存儲為 XML 文件,接下來我們需要一種方式來提交和運行該流程。Flowable 提供 Process Engine API 用於與 Flowable 引擎交互。 Flowable 非常靈活,並提供多種部署此 API 的方式。
鑑於 Flowable 是一個 Java API,我們可以通過簡單地包含所需的 JAR 文件將流程引擎包含在任何 Java 應用程序中。 我們可以很好地利用 Maven 來管理這些依賴項。
此外,Flowable 隨附了捆綁的 API,用於通過 HTTP 與 Flowable 交互。 我們可以使用這些 API 執行通常通過 Flowable API 執行的幾乎所有操作。
最後,Flowable 具有出色的 Spring 和 Spring Boot 集成支持! 我們將在教程中使用 Flowable 和 Spring Boot 集成。
5. 使用流程引擎創建演示應用程序
現在,讓我們創建一個簡單的應用程序,該應用程序封裝了 Flowable 流程引擎,並提供基於 HTTP 的 API 以與 Flowable API 交互。 此外,還可能存在一個基於 API 的 Web 或移動應用程序,以改善用户體驗,但為了簡化本教程,我們在此跳過這一步。
我們將演示應用程序作為 Spring Boot 應用程序創建。
5.1. 依賴關係
以下是我們需要從 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>7.0.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>我們需要的依賴項均可在 Maven Central 上找到:
- Spring Boot Web Starter — 這是 Spring Boot 的標準 Starter
- Flowable Spring Boot Starter — 用於 Spring Boot Flowable 引擎的必需 Starter
- H2 數據庫 — Flowable 需要一個數據庫來存儲數據,H2 是默認的內存數據庫
5.2. 流程定義
當啓動我們的 Spring Boot 應用程序時,它會嘗試自動加載位於“resources/processes” 文件夾下的所有流程定義。因此,讓我們創建一個名為“article-workflow.bpmn20.xml”的 XML 文件,其中包含我們上面創建的流程定義,並將其放置在該文件夾中。
5.3. 配置
我們知道 Spring Boot 對應用程序配置採取高度主觀化的方法,這一點同樣適用於 Flowable 作為 Spring Boot 的一部分。例如,當 Flowable 檢測到 classpath 上僅包含 H2 數據庫驅動時,它會自動配置 H2 用於使用。
顯然,任何可配置的方面都可以通過 應用程序屬性 進行自定義配置。但是,對於本教程,我們將堅持使用默認配置!
5.4. Java 委託
在我們的流程定義中,我們使用了幾個 Java 類,這些類被設計用於作為服務任務的一部分進行調用。 這些類實現了 JavaDelegate 接口,在 Flowable 中被稱為 Java 委託。 我們現在將定義這些 Java 委託的佔位類:
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.");
}
}顯然,我們必須用實際的服務替換這些佔位符類,才能發佈文章或發送電子郵件。
5.5. HTTP API
最後,讓我們創建一些端點,以便與流程引擎進行交互,並與我們已定義的流程進行操作。
我們將首先定義一個控制器,它將暴露三個端點:
@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);
}
}我們的控制器暴露了用於提交文章審核、獲取待審核文章列表以及提交文章審核的端點。 Article 和 Approval 是標準的 POJO,可在倉庫中找到。
我們實際上將大部分工作委派給 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);
}
}現在,這裏的代碼大部分都比較直觀,但讓我們來理解關鍵點:
- RuntimeService 用於為特定提交實例化流程
- TaskService 用於查詢和更新任務
- 將所有數據庫調用包裝在 Spring 支持的事務中
- 將作者、URL 等詳細信息存儲在 Map 中,並與流程實例一起保存;這些被稱為流程變量,並且我們可以在其流程定義中訪問它們,正如我們之前所見
現在,我們準備好測試我們的應用程序和流程引擎。一旦我們啓動應用程序,我們就可以簡單地使用 curl 或像 Postman 這樣的 REST 客户端與我們創建的端點進行交互。
6. 單元測試流程
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", "[email protected]");
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());
}
}這應該基本上看起來像一個標準的 Spring 單元測試,除了少量的註解,例如 @Deployment。現在,@Deployment 註解由 Flowable 提供,用於在測試方法周圍創建和刪除流程部署。
7. 理解流程部署
雖然本教程不會詳細介紹流程部署,但涵蓋一些重要的方面仍然值得。
通常,流程會被歸檔為業務檔案(Business Archive,BAR),並在應用程序中部署。在部署過程中,該檔案會被掃描,以查找流程定義等工件,並進行處理。您可能會注意到流程定義文件以“.bpmn20.xml”結尾的約定。
雖然我們在本教程中使用默認的內存 H2 數據庫,但實際上這無法在實際應用程序中使用,原因很簡單:內存數據庫不會在啓動時保留任何數據,並且在集羣環境中幾乎無法使用!因此,我們必須使用生產級關係型數據庫併為應用程序提供所需的配置.
雖然 BPMN 2.0 本身沒有版本控制的概念,Flowable 為流程創建了一個版本屬性,該屬性在數據庫中進行部署。如果通過“id”屬性標識的相同流程的更新版本被部署,則會創建一個新的條目,並且版本會被遞增。當我們嘗試通過“id”啓動流程時,流程引擎會檢索部署的最新流程定義。
如果我們使用前面討論的設計器為流程創建流程定義,我們已經擁有流程的可視化。我們可以將流程圖導出為圖像並將其放置在 XML 流程定義文件旁邊。如果遵循 Flowable 建議的標準命名約定(提供流程圖),則該圖像將由流程引擎與流程本身一起處理。此外,我們還可以通過 API 檢索該圖像!
8. 流程實例瀏覽歷史
在業務流程中,瞭解歷史記錄通常具有重要意義。這可能用於簡單的調試或複雜的法律審計目的。
Flowable 會記錄流程執行過程中發生的事情,並將其保存在數據庫中。 此外,Flowable 通過 API 使這些歷史記錄可供查詢和分析。 Flowable 記錄歷史數據基於六個實體,並且 HistoryService 提供了查詢所有這些實體的各種方法。
以下是一個簡單的查詢,用於檢索已完成的流程實例:
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> activities = historyService
.createHistoricActivityInstanceQuery()
.processInstanceId(processInstance.getId())
.finished()
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();如我們所見,查詢錄製數據的 API 相當靈活可組合。 在這個例子中,我們通過 ID 查詢已完成的流程實例,並按結束時間的升序排列。
9. 監控流程
監控是任何關鍵業務應用程序的關鍵組成部分,對於處理組織業務流程的應用程序尤其如此。Flowable 提供了多種選項,讓我們能夠實時監控流程。
Flowable 提供特定的 MBean,我們可以通過 JMX 訪問它們,不僅可以收集用於監控的數據,還可以執行許多其他活動。我們可以將其與任何標準 JMX 客户端集成,包括 <em >jconsole</em>,它與標準 Java 分發版一起提供。
使用 JMX 進行監控提供了許多選項,但相對複雜且耗時。然而,由於我們使用 Spring Boot,我們很幸運!
Spring Boot 提供 Actuator 端點,用於通過 HTTP 收集應用程序指標。我們可以無縫地將其與像 Prometheus 和 Grafana 這樣的工具堆棧集成,從而以最小的努力創建一個生產級別的監控工具。
Flowable 還提供了一個額外的 Actuator 端點,用於公開正在運行的流程的信息。 儘管不如通過 JMX 收集信息,但它速度快、簡單,最重要的是,它已經足夠了。
10. 結論
在本教程中,我們討論了業務流程及其在 BPMN 2.0 標準下的定義。 此外,我們還探討了 Flowable 流程引擎及其 API 的部署和執行能力,並展示瞭如何在 Java 應用(特別是 Spring Boot)中進行集成。
進一步探討中,我們討論了業務流程的其他重要方面,例如部署、可視化和監控。 毫無疑問,我們僅僅是觸及了業務流程和強大的 Flowable 引擎的冰山一角。 Flowable 擁有非常豐富的 API 以及充足的文檔支持。 然而,本教程應該已經激發了我們對這個主題的興趣!