diff --git a/.gitignore b/.gitignore
index 902f43c8b7e..5dfb8e5bded 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,15 +9,10 @@ target
.DS_Store
.vscode
*.bpmn/
-/userguide/src/en/index.html
-userguide/src/en/output/
migration.html
/modules/**/bin
modules/flowable-app-rest/.extract
modules/flowable-app-rest/src/main/resources/static/docs/specfile
-userguide-dmn/src/en/output
-userguide-form/src/en/output
-userguide-cmmn/src/en/output
docker/all-in-one/assets
k8s/flowable/charts
requirements.lock
diff --git a/docs/docusaurus/docs/bpmn/ch03-Configuration.md b/docs/docusaurus/docs/bpmn/ch03-Configuration.md
index 5102fab842e..cd7965bb664 100644
--- a/docs/docusaurus/docs/bpmn/ch03-Configuration.md
+++ b/docs/docusaurus/docs/bpmn/ch03-Configuration.md
@@ -374,13 +374,6 @@ Customizing the configuration of history storage is optional. This allows you to
-## Async history configuration
-
-\[Experimental\] Since Flowable 6.1.0 the async history feature has been added. When async history is enabled, the historic data will be persisted by a history job executor, instead of synchronous persistence as part of the runtime execution persistence.
-See [async history configuration](bpmn/ch10-History.md#async-history-configuration) for more details.
-
-
-
## Exposing configuration beans in expressions and scripts
By default, all beans that you specify in the flowable.cfg.xml configuration or in your own Spring configuration file are available to expressions and scripts. If you want to limit the visibility of beans in your configuration file, you can configure a property called beans in your process engine configuration. The beans property in ProcessEngineConfiguration is a map. When you specify that property, only beans specified in that map will be visible to expressions and scripts. The exposed beans will be exposed with the names as you specify in the map.
diff --git a/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md b/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md
index 87ae237a59d..c1bed727ab5 100644
--- a/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md
+++ b/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md
@@ -540,7 +540,7 @@ Here is a list of configuration properties that the Flowable Spring Boot support
# Process https://github.com/flowable/flowable-engine/tree/main/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/process/FlowableProcessProperties.java
flowable.process.definition-cache-limit=-1 # The maximum amount of process definitions available in the process definition cache. Per default it is -1 (all process definitions).
- flowable.process.enable-safe-xml=true # Enables extra checks on the BPMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml. Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of StaxSource during XML parsing.
+ flowable.process.enable-safe-xml=true # Enables extra checks on the BPMN xml that is parsed. Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of StaxSource during XML parsing.
flowable.process.servlet.load-on-startup=-1 # Load on startup of the Process dispatcher servlet.
flowable.process.servlet.name=Flowable BPMN Rest API # The name of the Process servlet.
flowable.process.servlet.path=/process-api # The context path for the Process rest servlet.
@@ -558,7 +558,7 @@ Here is a list of configuration properties that the Flowable Spring Boot support
# CMMN https://github.com/flowable/flowable-engine/tree/main/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/cmmn/FlowableCmmnProperties.java
flowable.cmmn.deploy-resources=true # Whether to perform deployment of resources, default is 'true'.
flowable.cmmn.deployment-name=SpringBootAutoDeployment # The name of the deployment for the CMMN resources.
- flowable.cmmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml. Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of StaxSource during XML parsing.
+ flowable.cmmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of StaxSource during XML parsing.
flowable.cmmn.enabled=true # Whether the CMMN engine needs to be started.
flowable.cmmn.resource-location=classpath*:/cases/ # The location where the CMMN resources are located.
flowable.cmmn.resource-suffixes=**.cmmn,**.cmmn11,**.cmmn.xml,**.cmmn11.xml # The suffixes for the resources that need to be scanned.
@@ -578,7 +578,7 @@ Here is a list of configuration properties that the Flowable Spring Boot support
# DMN https://github.com/flowable/flowable-engine/tree/main/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/dmn/FlowableDmnProperties.java
flowable.dmn.deploy-resources=true # Whether to perform deployment of resources, default is 'true'.
flowable.dmn.deployment-name=SpringBootAutoDeployment # The name of the deployment for the dmn resources.
- flowable.dmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml. Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of StaxSource during XML parsing.
+ flowable.dmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of StaxSource during XML parsing.
flowable.dmn.enabled=true # Whether the dmn engine needs to be started.
flowable.dmn.history-enabled=true # Whether the history for the DMN engine should be enabled.
flowable.dmn.resource-location=classpath*:/dmn/ # The location where the dmn resources are located.
diff --git a/docs/docusaurus/docs/bpmn/ch13-Applications.md b/docs/docusaurus/docs/bpmn/ch13-Applications.md
index f9b0b3aedb1..9e4ae9c8fb7 100644
--- a/docs/docusaurus/docs/bpmn/ch13-Applications.md
+++ b/docs/docusaurus/docs/bpmn/ch13-Applications.md
@@ -13,7 +13,7 @@ See [The Executable Jar Format](https://docs.spring.io/spring-boot/docs/current/
As mentioned before, the application can be deployed on a Tomcat server, and to get started this is probably the easiest approach when additional configuration settings are used. For this installation guide we’ll describe the installation of the application in a Tomcat server.
-1. Download a recent stable version of [Apache Tomcat](http://tomcat.apache.org). It has to be Jakarta Servlet 6 compliant
+1. Download a recent stable version of [Apache Tomcat](http://tomcat.apache.org). It has to be Jakarta Servlet 6 compliant (Tomcat 10 or later)
2. Download the latest stable [Flowable 7 version](http://www.flowable.org/downloads.html).
diff --git a/docs/docusaurus/docs/oss-introduction.md b/docs/docusaurus/docs/oss-introduction.md
index 5ccb0b79ab0..fb727ab3f77 100644
--- a/docs/docusaurus/docs/oss-introduction.md
+++ b/docs/docusaurus/docs/oss-introduction.md
@@ -21,7 +21,7 @@ The distribution contains most of the sources as JAR files. The source code for
### JDK 17+
-Flowable runs on a JDK higher than or equal to version 8. Go to [Oracle Java SE downloads](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and click on button "Download JDK". There are installation instructions on that page as well. To verify that your installation was successful, run java -version on the command line. That should print the installed version of your JDK.
+Flowable runs on a JDK higher than or equal to version 17. Go to [Oracle Java SE downloads](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and click on button "Download JDK". There are installation instructions on that page as well. To verify that your installation was successful, run java -version on the command line. That should print the installed version of your JDK.
### Modeling
diff --git a/docs/userguide/.gitignore b/docs/userguide/.gitignore
deleted file mode 100644
index eb6cfbcacb6..00000000000
--- a/docs/userguide/.gitignore
+++ /dev/null
@@ -1,25 +0,0 @@
-target
-*.iml
-*.ipr
-*.iws
-.idea
-.classpath
-.project
-.settings
-.DS_Store
-.vscode
-*.bpmn/
-src/en/base/output
-src/en/bpmn/output
-src/en/cmmn/output
-src/en/dmn/output
-src/en/form/output
-src/en/single/output
-
-
-src/zh_CN/base/output
-src/zh_CN/bpmn/output
-src/zh_CN/cmmn/output
-src/zh_CN/dmn/output
-src/zh_CN/form/output
-src/zh_CN/single/output
\ No newline at end of file
diff --git a/docs/userguide/README.md b/docs/userguide/README.md
deleted file mode 100644
index a6aebab661a..00000000000
--- a/docs/userguide/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-About
--------
-
-This project regroups all userguide sources
-
-Currently it contains :
-
-* [BPMN](/src/en/bpmn) : Business Process Model and Notation User Guide
-* [CMMN](/src/en/cmmn) : Case Management Model and Notation User Guide
-* [DMN](/src/en/dmn) : Decision Model and Notation User Guide
-* [FORM](/src/en/form) : Form engine User Guide
-* [SINGLE (Beta Version)](/src/en/single) : Unified version of all previous documentation
-
-Tooling
--------
-
-Install Asciidoctor: http://asciidoctor.org/
-
-We're using the 'pygments' library for syntax highlighting. This needs to be installed on your system too:
-```ruby
-gem install pygments.rb
-```
-
-
-Generating the docs
---------------------
-
-**Using build.xml**
-
-Simply select run the *build.docs.[bpmn|cmmn|dmn|form|single|all]* goal and it will generate both a html & pdf version.
-All generated files will be available in the root project **target** folder.
-
-
-**From scripts folder**
-
-Go to the [scripts Folder](/scripts)
-* Call the generate-all.sh [bpmn|cmmn|dmn|form|single] to generate for a single project both html & pdf version.
-```bash
-# Genate BPMN documentation in html & pdf format
-> ./generate-all.sh bpmn
-```
-* Call the generate-html.sh [bpmn|cmmn|dmn|form|single] to generate html.
-```bash
-# Genate Form documentation in html format
-> ./generate-html.sh form
-```
-* Call the generate-pdf.sh [bpmn|cmmn|dmn|form|single] to generate pdf.
-```bash
-# Genate DMN documentation in pdf format
-> ./generate-pdf.sh dmn
-```
-
-**From each project folder**
-
-Use **./generate-html.sh** for html only and likewise **./generate-pdf.sh** for pdf only.
-
-
-Docs on the docs
-----------------
-
-The html is generated using the **'index-html.adoc'** file per project. The pdf generation uses the **'index-pdf.adoc'** file per project. Both reference a shared **'index-common.adoc'** file for the actual content, but define different parameters in the preamble.
-
-When building the html doc, following files get included automatically:
-
-* **base/flowable.css** : this is the stylesheet for the docs. The css will be included inline in the html docs.
-* **base/docinfo.html** : this file gets included at the top of the html file. It contains the tocbot library and a little script to initialize the dynamic table of contents.
-
-
-NB
--------
-We still use Ant as building tool because Asciidoctor Maven Plugin does not support the current level of quality for the generated documentation. We "still"
-have to use asciidoc command line.
diff --git a/docs/userguide/build.xml b/docs/userguide/build.xml
deleted file mode 100644
index 457b0ed1d90..00000000000
--- a/docs/userguide/build.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/userguide/scripts/clean.sh b/docs/userguide/scripts/clean.sh
deleted file mode 100755
index 824ea2fc1cb..00000000000
--- a/docs/userguide/scripts/clean.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-if [ -z "$1" ]
-then
- echo -e "Usage: \n${0##*/} all \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form"
- exit 1
-fi
-
-if [ $1 == all ]
-then
- rm -rf ../src/en/single/output
- rm -rf ../src/en/bpmn/output
- rm -rf ../src/en/cmmn/output
- rm -rf ../src/en/dmn/output
- rm -rf ../src/en/form/output
-else
- rm -rf ../src/en/$1/output
-fi
diff --git a/docs/userguide/scripts/generate-all.sh b/docs/userguide/scripts/generate-all.sh
deleted file mode 100755
index 25564ccbb5a..00000000000
--- a/docs/userguide/scripts/generate-all.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-if [ -z "$1" ]
-then
- echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form \n${0##*/} single"
- exit 1
-fi
-
-if [ $1 == bpmn ] || [ $1 == cmmn ] || [ $1 == dmn ] || [ $1 == form ] || [ $1 == single ]
-then
- ./clean.sh $1
- ./generate-html.sh $1
- ./generate-pdf.sh $1
-else
- echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form"
- exit 1
-fi
-
-
diff --git a/docs/userguide/scripts/generate-html.sh b/docs/userguide/scripts/generate-html.sh
deleted file mode 100755
index 0a096702bce..00000000000
--- a/docs/userguide/scripts/generate-html.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-if [ -z "$1" ]
-then
- echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form \n${0##*/} single"
- exit 1
-fi
-
-if [ $1 == bpmn ] || [ $1 == cmmn ] || [ $1 == dmn ] || [ $1 == form ] || [ $1 == single ]
-then
- cd ../src/en/$1
- ./generate-html.sh
-else
- echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form"
- exit 1
-fi
-
-
diff --git a/docs/userguide/scripts/generate-pdf.sh b/docs/userguide/scripts/generate-pdf.sh
deleted file mode 100755
index 5a92dc9ca5f..00000000000
--- a/docs/userguide/scripts/generate-pdf.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-if [ -z "$1" ]
-then
- echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form \n${0##*/} single"
- exit 1
-fi
-
-if [ $1 == bpmn ] || [ $1 == cmmn ] || [ $1 == dmn ] || [ $1 == form ] || [ $1 == single ]
-then
- cd ../src/en/$1
- ./generate-pdf.sh
-else
- echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form"
- exit 1
-fi
-
-
diff --git a/docs/userguide/src/zh_CN/base/docinfo.html b/docs/userguide/src/zh_CN/base/docinfo.html
deleted file mode 100755
index 7042ec64987..00000000000
--- a/docs/userguide/src/zh_CN/base/docinfo.html
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
diff --git a/docs/userguide/src/zh_CN/base/flowable.css b/docs/userguide/src/zh_CN/base/flowable.css
deleted file mode 100755
index 6fc2afdc123..00000000000
--- a/docs/userguide/src/zh_CN/base/flowable.css
+++ /dev/null
@@ -1,247 +0,0 @@
-
-/* normalize.css */
-
-button,hr,input{overflow:visible}audio,canvas,progress,video{display:inline-block}progress,sub,sup{vertical-align:baseline}html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} menu,article,aside,details,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{}button,select{text-transform:none}[type=submit], [type=reset],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}[hidden],template{display:none}/*# sourceMappingURL=normalize.min.css.map */
-
-/* tocbot 2.1.4 */
-
-.toc{overflow-y:auto}.toc>ul{overflow:hidden;position:relative}.toc-list{margin:0;padding-left:10px}a.toc-link{color:currentColor;height:100%}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 300ms ease-in-out}.is-collapsed{max-height:0}.is-position-fixed{position:fixed !important;top:0}.is-active-link{font-weight:700}.toc-link::before{background-color:#f9f9fb;content:' ';display:inline-block;height:inherit;left:8px;margin-top:-1px;position:absolute;width:2px}.is-active-link::before{background-color:#54BC4B}
-
-
-/* Activiti Specific */
-
-body {
- color: #494d55;
- font-size: 16px;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-html, body {
- height: 100%;
- width: 100%;
- background: #f9f9f9;
- font-family: "Helvetica Neue",Helvetica,Roboto,Arial,sans-serif;
- color: #484848
-}
-
-.page-wrapper {
- min-height: 100%;
- /* equal to footer height */
- margin-bottom: -50px;
-}
-
-.page-wrapper:after {
- content: "";
- display: block;
- height: 50px;
-}
-
-#header {
- position:fixed;
- top:0px;
- z-index:100000;
- width:100%;
-}
-
-#header > h1 {
- background: #a0cc47;
- color: #f9f9f9;
- border-bottom: 2px solid #042944;
- padding: 20px 0 20px 20px;
- font-size: 40px;
- font-weight: 800;
- line-height: 1.1;
- margin: 0;
-}
-
-#header > h1:before {
- background:url('images/logo.png');
- background-size: 337px 54px; background-repeat: no-repeat;
- width: 337px;
- height: 54px;
- display:inline-block;
- content:'';
- margin-right: 30px;
-}
-
-#author {
- margin-left: 25%;
- font-size: 40px;
-}
-
-#content {
- margin: 129px 0 0 27%;
- padding: 10px 40px 0 20px;
- padding-right: 40px;
- line-height: 1.7;
- width: 65%;
- overflow-x: auto;
-}
-
-h2, h3, h4, h5, h6 {
- color: #00345a;
-}
-
-h2 {
- font-size: 26px;
- margin-top: 0;
- margin-bottom: 20px;
- font-weight: bold;
- padding-bottom: 10px;
- border-bottom: 1px solid #d7d7d7;
-}
-
-h3 {
- font-size: 18px;
- margin-top: 0;
- margin-bottom: 0;
- font-weight: bold;
- padding-bottom: 10px;
- /*border-bottom: 1px solid #d7d7d7;*/
-}
-
-h4 {
- font-size: 16px;
- font-weight: bold;
-}
-
-h5 {
- font-size: 14px;
- font-weight: bold;
-}
-
-h6, h7 {
- font-size: 14px;
- font-weight: bold;
- margin-top: 0;
- margin-bottom: 0;
-}
-
-.sect1, .sect2 {
- margin-bottom: 20px;
-}
-
-.clear
-{
- clear: both;
-}
-
-.note, .listingblock, .literalblock{
- padding-left: 8px;
- padding-right: 8px;
- margin-bottom: 14px;
- background-color: #f7f7f9;
- border: 1px solid #e1e1e8;
- border-radius: 4px;
- color: #808080;
-}
-
-table.tableblock {
- width: 100%;
- max-width: 100%;
- margin-bottom: 20px;
- background-color: transparent;
- border-spacing: 0;
- border-collapse: collapse;
- border: 1px solid #ddd;
- table-layout: fixed;
-}
-
-table.tableblock>caption+thead>tr:first-child>td, table.tableblock>caption+thead>tr:first-child>th, table.tableblock>colgroup+thead>tr:first-child>td, table.tableblock>colgroup+thead>tr:first-child>th, table.tableblock>thead:first-child>tr:first-child>td, table.tableblock>thead:first-child>tr:first-child>th {
- border-top: 0;
-}
-
-table.tableblock > thead > tr > th {
- border-bottom-color: #8bd6d8;
-}
-
-table.tableblock>thead>tr>th {
- vertical-align: bottom;
- border-bottom: 1px solid #ddd;
-}
-
-table.tableblock>tbody>tr>td, table.tableblock>tbody>tr>th, table.tableblock>tfoot>tr>td, table.tableblock>tfoot>tr>th, table.tableblock>thead>tr>td, table.tableblock>thead>tr>th {
- padding: 8px;
- line-height: 1.42857143;
- vertical-align: top;
- border-top: 1px solid #ddd;
-}
-
-th {
- text-align: left;
-}
-
-table.tableblock > tbody > tr:nth-of-type(odd) {
- background-color: #f5f5f5;
-}
-
-table.tableblock > tbody > tr:nth-of-type(odd) {
- background-color: #f9f9f9;
-}
-
-td > p {
- margin:0;
-}
-
-td.content {
- white-space: normal;
-}
-
-pre, td, th {
- white-space: pre-wrap;
- white-space: -moz-pre-wrap;
- white-space: -pre-wrap;
- white-space: -o-pre-wrap;
- word-wrap: break-word;
-}
-
-img {
- max-width: 100%;
-}
-
-a {
- color: #007387;
-}
-
-a:hover {
- color: #004c59;
-}
-
-#toc-parent {
- width: 25%;
- float: left;
- height: 100%;
- overflow-y: auto;
- position: fixed;
- padding: 10px;
- border-right: 1px solid #ccc;
-}
-
-#generated-toc {
- width: 100%;
- height: 100%;
- font-size: 16px;
-}
-
-.toc-link {
- text-decoration: none;
-}
-
-.toc-list {
- margin: 0 20px 0 10px;
-}
-
-.toc-list-item {
- padding: 4px 0 4px 0;
-}
-
-
-div.sect5 p {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-div.sect5 code {
- font-family: "Helvetica Neue",Helvetica,Roboto,Arial,sans-serif;
-}
\ No newline at end of file
diff --git a/docs/userguide/src/zh_CN/base/header-Introduction.adoc b/docs/userguide/src/zh_CN/base/header-Introduction.adoc
deleted file mode 100755
index 8fde0eb9304..00000000000
--- a/docs/userguide/src/zh_CN/base/header-Introduction.adoc
+++ /dev/null
@@ -1,75 +0,0 @@
-[[license]]
-=== 翻译(说明)
-
-由[分享牛Flowable中国社区] 翻译,任何意见建议,欢迎联系QQ:3152981878。
-如果想一起成为开源代码贡献人员,欢迎大家加入qq交流群为社区贡献添砖加瓦。qq贡献群:1023773998
-
-
-=== 协议
-
-Flowable在link:$$http://www.apache.org/licenses/LICENSE-2.0.html$$[Apache V2 协议]下发布。
-
-[[download]]
-
-=== 下载
-
-link:$$http://www.flowable.org/downloads.html$$[http://www.flowable.org/downloads.html]
-[[sources]]
-
-=== 源码
-
-Flowable的发布包里包含了大部分源码,以JAR文件方式提供。Flowable的源码也可以通过以下链接获得:
- link:$$https://github.com/flowable/flowable-engine$$[https://github.com/flowable/flowable-engine]
-
-
-[[required.software]]
-
-
-=== 必要的软件
-
-==== JDK 8+
-
-运行Flowable需要JDK 8或以上版本。可以访问 link:$$http://www.oracle.com/technetwork/java/javase/downloads/index.html$$[Oracle Java SE downloads页面] 点击“Download JDK”按钮获取。该页面上也有安装指导。安装完成后,可以执行 +java -version+ 。能看到JDK的版本信息就说明安装成功了。
-
-==== IDE
-
-可以自行选择用于Flowable开发的IDE。如果想要使用Flowable Designer,则需要Eclipse Mars或Neon。
-到 link:$$http://www.eclipse.org/downloads/$$[Eclipse下载页面]选择Eclipse版本并下载。解压下载的文件,
-然后执行++eclipse++文件夹下的eclipse文件。手册后续有专门一章介绍如何<>。
-
-
-[[reporting.problems]]
-
-=== 反馈问题
-
-我们希望开发者在报告或提问之前,先看看link:$$http://www.catb.org/~esr/faqs/smart-questions.html$$[提问的智慧]。
-
-看完提问的智慧,你可以在link:$$http://forums.flowable.org$$[用户论坛]提问、评论以及提交改进建议,也可以在link:$$https://github.com/flowable/flowable-engine/issues$$[我们的Github问题跟踪系统]创建bug报告。
-
-
-[[experimental]]
-
-=== 实验性功能
-
-标记有**[实验性]**的章节介绍的功能还不够稳定。
-
-++.impl.++包下的类都是内部实现类,不保证稳定。但是,在用户手册中作为配置参数介绍的类则是被官方支持的,可以保证稳定。
-
-
-[[internal]]
-
-=== 内部实现类
-
-在JAR文件中,所有++.impl.++包下的类(比如++org.flowable.engine.impl.db++)都是实现类,只应在内部使用。实现类中的所有类或接口都不保证稳定。
-
-[[_versioning_strategy]]
-=== 版本策略
-
-使用三个整数的形式标记版本:**MAJOR.MINOR.MICRO**。其中 **MAJOR**版本代表核心引擎的演进。**MINOR**版本代表新功能与新API。**MICRO**版本代表bug修复与改进。
-
-总的来说,Flowable希望在**MINOR**与**MICRO**版本中,对所有非内部实现类保持“源代码兼容性”,即应用可以正确构建,且不改变语义。Flowable也希望在**MINOR**与**MICRO**版本中,保持“二进制兼容性”,即用新版本的Flowable直接替换老版本的Jar文件,仍然可以正常工作。
-
-如果在**MINOR**版本中修改了API,将保留原有版本,并使用__@Deprecated__注解。这种废弃的API将在两个**MINOR**版本之后移除。
-
-[[translator_info]]
-
diff --git a/docs/userguide/src/zh_CN/base/header-rest.adoc b/docs/userguide/src/zh_CN/base/header-rest.adoc
deleted file mode 100755
index 38a7dbbbec4..00000000000
--- a/docs/userguide/src/zh_CN/base/header-rest.adoc
+++ /dev/null
@@ -1,246 +0,0 @@
-[[_general_flowable_rest_principles]]
-=== Flowable REST一般原则
-
-[[_installation_and_authentication]]
-==== 安装与认证
-
-Flowable为Flowable引擎提供了REST API,可以通过在servlet容器(如Apache Tomcat)中部署flowable-rest.war文件来安装。另外,也可以通过在应用中引入servlet(包括对应的映射),并将所有flowable-rest的依赖加入classpath的方式使用。
-
-默认情况下Flowable引擎会连接至一个H2内存数据库。可以通过__WEB-INF/META-INF/flowable-app__文件夹下的flowable-app.properties文件修改数据库设置。REST API使用JSON格式( http://www.json.org ),并基于Spring MVC( http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html )构建。
-
-默认情况下访问任何REST资源都需要具有__rest-access-api__权限的合法用户。如果需要任何合法用户都可以访问REST API,可以将__flowable.rest.app.authentication-mode__设置为__any-user__(这也是之前版本Flowable的默认设置)。
-
-通过如下参数设置可以访问REST API的默认用户:
-
-----
-flowable.rest.app.admin.user-id=rest-admin
-flowable.rest.app.admin.password=test
-flowable.rest.app.admin.first-name=Rest
-flowable.rest.app.admin.last-name=Admin
-----
-
-当REST应用启动时,如果用户不存在或无法找到,则会创建该用户。这个用户会被赋予访问REST API所需的__access-rest-api__权限。**请不要忘记修改这个用户的密码**。如果未设置__flowable.rest.app.admin.user-id__,则不会创建用户或权限。也因为此,在初始化完成后删除这些参数,并不会删除之前已经配置的用户或权限。
-
-使用基础HTTP访问认证,因此在请求时,需要在HTTP-header中添加 __Authorization: Basic ...==__ 。也可以在请求url中包含用户名与密码(如 __http://username:password@localhost:8080/xyz__)。
-
-**建议使用基础认证时,同时使用HTTPS。**
-
-[[_configuration_2]]
-==== 配置
-
-Flowable REST web应用使用Spring Java Configuration来启动Flowable引擎,使用Spring security定义基础认证安全,并为为特定的变量处理定义了变量转换。
-有少量参数可以通过修改WEB-INF/classes文件夹下的engine.properties文件定义。
-如果需要高级配置选项,可以在flowable-custom-context.xml文件中覆盖默认的Spring bean,这个文件也在WEB-INF/classes文件夹下。
-该文件中已经以注释形式提供了示例配置。也可以在该文件中定义一个新的命名为restResponsefactory的Spring bean,覆盖默认的RestResponseFactory,并使用自定义实现类。
-
-[[restUsageInTomcat]]
-==== 在Tomcat中使用
-
-
-由于link:$$http://tomcat.apache.org/tomcat-8.0-doc/security-howto.html$$[Tomcat中的默认安全参数],**默认不能使用转义斜线符(++%2F++与++%5C++)(将返回400)。**这可能会影响部署资源与其数据URL,因为URL可能包含转义斜线符。
-
-当发现400异常结果时,可以设置下列系统参数:
-
-__-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true__
-
-最佳实践是(在post/put JSON时),在下面介绍的HTTP请求中,永远将**Accept**与**Content-Type**HTTP头设置为**application/json**。
-
-[[_methods_and_return_codes]]
-==== 方法与返回码
-
-.HTTP方法与对应操作
-[options="header"]
-|===============
-|方法|操作
-|+GET+|获取单个资源,或获取一组资源。
-|+POST+|创建一个新资源。在查询结构太复杂,不能放入GET请求的查询URL中时,也用于执行资源查询。
-|+PUT+|更新一个已有资源的参数。也用于调用已有资源提供的操作。
-|+DELETE+|删除一个已有资源。
-
-|===============
-
-
-.HTTP方法响应码
-[options="header"]
-|===============
-|响应|描述
-|++200 - Ok++|操作成功,返回响应(++GET++与++PUT++请求)。
-|++201 - 已创建++|操作成功,已经创建了实体,并在响应体中返回(++POST++请求)。
-|++204 - 无内容++|操作成功,已经删除了实体,因此没有返回的响应体(++DELETE++请求)。
-|++401 - 未认证++|操作失败。操作要求设置认证头。如果请求中有认证头,则提供的鉴证并不合法,或者用户未被授权进行该操作。
-|++403 - 禁止++|操作被禁止,且不应重试。这不是鉴证或授权的问题,而是说明不允许该操作。例如:无论任何用户或流程/任务的状态,删除一个运行中流程的任务是且永远是不允许的。
-|++404 - 未找到++|操作失败。请求的资源未找到。
-|++405 - 不允许的方法++|操作失败。使用的方法不能用于该资源。例如,更新(PUT)部署资源将返回++405++响应码。
-|++409 - 冲突++|操作失败。该操作导致更新一个已被其他操作更新的资源,因此本更新不再有效。也可以表示正在为一个集合创建一个资源,但该标识符已存在。
-|++415 - 不支持的媒体类型++|操作失败。请求提包含了不支持的媒体类型。也会发生在请求体JSON中包含了未知的属性或值,但没有可用的格式/类型来处理的情况。
-|++500 - 服务器内部错误++|操作失败。执行操作时发生了未知异常。响应体中包含了错误的细节。
-
-|===============
-
-
-HTTP响应的media-type总是++application/json++,除非请求的是二进制内容(例如部署资源数据)。这时将使用内容的media-type。
-
-[[_error_response_body]]
-==== 错误响应体
-
-当发生错误时(可能是客户端或服务器端的错误,4XX及5XX状态码),响应体会包含一个描述了发生的错误的对象。任务未找到时的404状态的例子:
-
-[source,json,linenums]
-----
-{
- "statusCode" : 404,
- "errorMessage" : "Could not find a task with id '444'."
-}
-----
-
-[[_request_parameters]]
-==== 请求参数
-
-[[_url_fragments]]
-===== URL片段
-
-作为url的一部分的参数(例如,++http://host/flowable-rest/service/repository/deployments/{deploymentId}++中的deploymentId参数),如果包含特殊字符,则需要进行合适的转义(参见link:$$https://en.wikipedia.org/wiki/Percent-encoding$$[URL编码或百分号编码])。大多数框架都内建了这个功能,但要记得考虑它。特别是对可能包含斜线符的段落(例如部署资源),就必须要做转义。
-
-[[_rest_url_query_parameters]]
-===== Rest URL查询参数
-
-作为查询字符串添加在URL中的参数(例如++http://host/flowable-rest/service/deployments?name=Deployment++中的name参数)可以使用下列类型。在相应的REST-API文档中也会提到:
-
-
-.URL查询参数类型
-[options="header"]
-|===============
-|类型|格式
-|String|纯文本参数。可以包含任何URL允许的合法字符。对于++XXXLike++参数,字符串可能会包含通配符++%++(需要进行URL编码)。可以进行like搜索,例如,'Tas%'将匹配所有以'Tas'开头的值。
-|Integer|整形参数。只能包含数字型非小数值,在-2.147.483.648至2.147.483.647之间。
-|Long|长整形参数。只能包含数字型非小数值,在-9.223.372.036.854.775.808至9.223.372.036.854.775.807之间。
-|Boolean|boolean型参数。可以为++true++或++false++。任何其他值都会导致'++405 - 错误请求++'响应码。
-|Date|日期型参数。使用ISO-8601日期格式(参考link:$$http://en.wikipedia.org/wiki/ISO_8601$$[wikipedia中的ISO-8601]),使用时间与日期部分(例如++2013-04-03T23:45Z++)。
-
-|===============
-
-
-[[restJsonBody]]
-
-
-===== JSON body 参数
-
-.JSON参数类型
-[options="header"]
-|===============
-|类型|格式
-|String|纯文本参数。对于++XXXLike++参数,字符串可能会包含通配符++%++。可以进行like搜索。例如,'Tas%'将匹配所有以'Tas'开头的值。
-|Integer|整形参数,使用JSON数字。只能包含数字型非小数值,在-2.147.483.648至2.147.483.647之间。
-|Long|长整形参数,使用JSON数字。只能包含数字型非小数值,在-9.223.372.036.854.775.808至9.223.372.036.854.775.807之间。
-|Date|日期型参数,使用JSON文本。使用ISO-8601日期格式(参考link:$$http://en.wikipedia.org/wiki/ISO_8601$$[wikipedia中的ISO-8601]),使用时间与日期组分(例如++2013-04-03T23:45Z++)。
-
-|===============
-
-
-[[restPagingAndSort]]
-
-
-===== 分页与排序
-
-
-分页与排序参数可以作为查询字符串加入URL中(例如++http://host/flowable-rest/service/deployments?sort=name++中的name参数)。
-
-.JSON查询变量参数
-[options="header"]
-|===============
-|参数|默认值|描述
-|sort|各查询实现不同|排序键的名字,在各查询实现中默认值与可用值都不同。
-|order|asc|排序顺序,可以是'asc'(顺序)或'desc'(逆序)。
-|start|0|对结果分页的参数。默认结果从0开始。
-|size|10|对结果分页的参数。默认大小为10.
-
-|===============
-
-[[restQueryVariable]]
-
-
-===== JSON查询变量格式
-
-[source,json,linenums]
-----
-
-{
- "name" : "variableName",
- "value" : "variableValue",
- "operation" : "equals",
- "type" : "string"
-}
-----
-
-
-.JSON查询变量参数
-[options="header"]
-|===============
-|参数|必填|描述
-|name|否|包含在查询中的变量名。在有些使用'++equals++'的查询中可以为空,查询**任意变量名**为给定值的资源。
-|value|是|包含在查询中的变量值,需要使用给定类型的正确格式。
-|operator|是|查询使用的操作,可以为下列值:++equals, notEquals, equalsIgnoreCase, notEqualsIgnoreCase, lessThan, greaterThan, lessThanOrEquals, greaterThanOrEquals++与++like++。
-|type|否|所用变量的类型。当省略时,会从++value++参数推理类型。任何JSON文本值都使用是++string++类型,JSON boolean值使用++boolean++类型,JSON数字使用++long++或++integer++,取决于数字的大小。建议在有疑惑时明确指定类型。其他支持的类型列在下面。
-
-|===============
-
-
-.默认查询JSON类型
-[options="header"]
-|===============
-|类型名|描述
-|string|值处理转换为++java.lang.String++。
-|short|值处理转换为++java.lang.Integer++。
-|integer|值处理转换为++java.lang.Integer++。
-|long|值处理转换为++java.lang.Long++。
-|double|值处理转换为++java.lang.Double++。
-|boolean|值处理转换为++java.lang.Boolean++。
-|date|值处理转换为++java.util.Date++。JSON字符串将使用ISO-8601日期格式转换。
-
-|===============
-
-
-[[restVariables]]
-
-===== 变量表示
-
-读取与写入变量(执行选择)时,REST API都使用通用原则与JSON格式。变量的JSON表示为:
-
-
-[source,json,linenums]
-----
-{
- "name" : "variableName",
- "value" : "variableValue",
- "valueUrl" : "http://...",
- "type" : "string"
-}
-----
-
-.变量的JSON属性
-[options="header"]
-|===============
-|参数|必填|描述
-|name|是|变量名。
-|value|否|变量的值。当写入变量且省略了++value++时,会使用++null++作为value。
-|valueUrl|否|当读取++binary++或++serializable++类型的变量时,这个属性将指向可用于获取原始二进制数据的URL。
-|type|否|变量的类型。查看下面的表格了解类型的更多信息。当写入变量且省略了这个值时,将使用请求的原始JSON属性类型推断,限制在++string++, ++double++, ++integer++与++boolean++中。建议总是包含类型,以确保不会错误推断类型。
-
-|===============
-
-.变量类型
-[options="header"]
-|===============
-|类型名|描述
-|string|值按照++java.lang.String++处理。写入变量时使用原始JSON文本。
-|integer|值按照++java.lang.Integer++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。
-|short|值按照++java.lang.Short++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。
-|long|值按照++java.lang.Long++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。
-|double|值按照++java.lang.Double++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。
-|boolean|值按照++java.lang.Boolean++处理。按约定写入变量时使用JSON boolean。
-|date|值按照++java.util.Date++处理。写入变量时将转换为ISO-8601日期格式。
-
-|===============
-
-
-可以使用自定义JSON表示,以支持额外的变量类型(既可以是简单值,也可以是复杂/嵌套的JSON对象)。通过扩展++org.flowable.rest.service.api.RestResponseFactory++的++initializeVariableConverters()++方法,可以添加额外的++org.flowable.rest.service.api.engine.variable.RestVariableConverter++类,用于将POJO转换为适合通过REST传输的格式,以及将REST值转换为POJO。实际转换JSON使用Jackson。
diff --git a/docs/userguide/src/zh_CN/base/images/li-chevron.png b/docs/userguide/src/zh_CN/base/images/li-chevron.png
deleted file mode 100755
index 4e966354cba..00000000000
Binary files a/docs/userguide/src/zh_CN/base/images/li-chevron.png and /dev/null differ
diff --git a/docs/userguide/src/zh_CN/base/images/logo.png b/docs/userguide/src/zh_CN/base/images/logo.png
deleted file mode 100755
index ef9996664e7..00000000000
Binary files a/docs/userguide/src/zh_CN/base/images/logo.png and /dev/null differ
diff --git a/docs/userguide/src/zh_CN/base/images/logo@2x.png b/docs/userguide/src/zh_CN/base/images/logo@2x.png
deleted file mode 100755
index d3b55d38e59..00000000000
Binary files a/docs/userguide/src/zh_CN/base/images/logo@2x.png and /dev/null differ
diff --git a/docs/userguide/src/zh_CN/bpmn/ch02-GettingStarted.adoc b/docs/userguide/src/zh_CN/bpmn/ch02-GettingStarted.adoc
deleted file mode 100755
index 21aecc39667..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch02-GettingStarted.adoc
+++ /dev/null
@@ -1,583 +0,0 @@
-[[_getting_started]]
-== 开始
-
-[[_what_is_flowable]]
-=== Flowable是什么?
-
-Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准),
-创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据,等等。这个章节将用一个可以在你自己的开发环境中使用的例子,逐步介绍各种概念与API。
-
-Flowable可以十分灵活地加入你的应用/服务/构架。可以将JAR形式发布的Flowable库加入应用或服务,来__嵌入__引擎。
-以JAR形式发布使Flowable可以轻易加入任何Java环境:Java SE;Tomcat、Jetty或Spring之类的servlet容器;JBoss或WebSphere之类的Java EE服务器,等等。
-另外,也可以使用Flowable REST API进行HTTP调用。也有许多Flowable应用(Flowable Modeler, Flowable Admin, Flowable IDM 与 Flowable Task),提供了直接可用的UI示例,可以使用流程与任务。
-
-所有使用Flowable方法的共同点是核心引擎。核心引擎是一组服务的集合,并提供管理与执行业务流程的API。
-下面的教程从设置与使用核心引擎的介绍开始。后续章节都建立在之前章节中获取的知识之上。
-
-* <>展示了以最简单的方式运行Flowable的方法:只使用Java SE的标准Java main方法。这里也会介绍许多核心概念与API。
-* <>章节展示了如何通过REST运行及使用相同的API。
-* <>章节将介绍直接可用的Flowable UI示例的基本方法。
-
-[[_flowable_and_activiti]]
-=== Flowable与Activiti
-
-Flowable是Activiti(Alfresco持有的注册商标)的fork。在下面的章节中,你会注意到包名,配置文件等等,都使用__flowable__。
-
-[[getting.started.command.line]]
-=== 构建命令行程序
-
-[[_creating_a_process_engine]]
-==== 创建流程引擎
-
-在这个初步教程中,将构建一个简单的例子,以展示如何创建一个Flowable流程引擎,介绍一些核心概念,并展示如何使用API。
-截图时使用的是Eclipse,但实际上可以使用任何IDE。我们使用Maven获取Flowable依赖及管理构建,但是类似的任何其它方法也都可以使用(Gradle,Ivy,等等)。
-
-我们将构建的例子是一个简单的__请假(holiday request)__流程:
-
-* __雇员(employee)__申请几天的假期
-* __经理(manager)__批准或驳回申请
-* 我们会模拟将申请注册到某个外部系统,并给雇员发送结果邮件
-
-首先,通过__File -> New -> Other -> Maven Project__创建一个新的Maven项目
-
-image::images/getting.started.new.maven.png[align="center"]
-
-在下一界面中,选中'__create a simple project (skip archetype selection)__'
-
-image::images/getting.started.new.maven2.png[align="center"]
-
-填入__'Group Id'__与__'Artifact id'__:
-
-image::images/getting.started.new.maven3.png[align="center"]
-
-这样就建立了空的Maven项目,然后添加两个依赖:
-
-* Flowable流程引擎。使我们可以创建一个ProcessEngine流程引擎对象,并访问Flowable API。
-* 一个内存数据库。本例中为H2,因为Flowable引擎在运行流程实例时,需要使用数据库来存储执行与历史数据。
-请注意H2依赖包含了数据库__及__驱动。如果使用其他数据库(例如PostgreSQL,MySQL等),需要添加对应的数据库驱动依赖。
-
-在__pom.xml__文件中添加下列行:
-
-[source,xml,linenums]
-----
-
-
- org.flowable
- flowable-engine
- 6.5.0.event-SNAPSHOT
-
-
- com.h2database
- h2
- 1.3.176
-
-
-----
-
-如果由于某些原因,依赖JAR无法自动获取,可以右键点击项目,并选择'__Maven -> Update Project__'以强制手动刷新(一般不会需要这么操作)。
-在这个项目中的'__Maven Dependencies__'下,可以看到__flowable-engine__与许多其他(传递的)依赖。
-
-创建一个新的Java类,并添加标准的Java main方法:
-
-[source,java,linenums]
-----
-package org.flowable;
-
-public class HolidayRequest {
-
- public static void main(String[] args) {
-
- }
-
-}
-----
-
-首先要做的是初始化**ProcessEngine**流程引擎实例。这是一个线程安全的对象,因此通常只需要在一个应用中初始化一次。
-__ProcessEngine__由**ProcessEngineConfiguration**实例创建。该实例可以配置与调整流程引擎的设置。
-通常使用一个配置XML文件创建__ProcessEngineConfiguration__,但是(像在这里做的一样)也可以编程方式创建它。
-__ProcessEngineConfiguration__所需的最小配置,是数据库JDBC连接:
-
-[source,java,linenums]
-----
-package org.flowable;
-
-import org.flowable.engine.ProcessEngine;
-import org.flowable.engine.ProcessEngineConfiguration;
-import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
-
-public class HolidayRequest {
-
- public static void main(String[] args) {
- ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
- .setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1")
- .setJdbcUsername("sa")
- .setJdbcPassword("")
- .setJdbcDriver("org.h2.Driver")
- .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
-
- ProcessEngine processEngine = cfg.buildProcessEngine();
- }
-
-}
-----
-
-在上面的代码中,第10行创建了一个__独立(standalone)__配置对象。这里的__'独立'__指的是引擎是完全独立创建及使用的(而不是在Spring环境中使用,这时需要使用__SpringProcessEngineConfiguration__类代替)。第11至14行中,传递了一个内存H2数据库实例的JDBC连接参数。
-重要:请注意这样的数据库在JVM重启后会消失。如果需要永久保存数据,需要切换为持久化数据库,并相应切换连接参数。
-第15行中,设置了__true__,确保在JDBC参数连接的数据库中,数据库表结构不存在时,会创建相应的表结构。
-另外,Flowable也提供了一组SQL文件,可用于手动创建所有表的数据库表结构。
-
-然后使用这个配置创建**ProcessEngine**对象(第17行)。
-
-这样就可以运行了。在Eclipse中最简单的方法是右键点击类文件,选择__Run As -> Java Application__ :
-
-image::images/getting.started.run.main.png[align="center"]
-
-应用运行没有问题,但也没有在控制台提供有用的信息,只有一条消息提示日志没有正确配置:
-
-image::images/getting.started.console.logging.png[align="center"]
-
-Flowable使用link:$$http://www.slf4j.org/$$[SLF4J]作为内部日志框架。在这个例子中,我们使用log4j作为SLF4J的实现。因此在pom.xml文件中添加下列依赖:
-
-[source,xml,linenums]
-----
-
- org.slf4j
- slf4j-api
- 1.7.21
-
-
- org.slf4j
- slf4j-log4j12
- 1.7.21
-
-----
-
-Log4j需要一个配置文件。在__src/main/resources__文件夹下添加__log4j.properties__文件,并写入下列内容:
-
-----
-log4j.rootLogger=DEBUG, CA
-
-log4j.appender.CA=org.apache.log4j.ConsoleAppender
-log4j.appender.CA.layout=org.apache.log4j.PatternLayout
-log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
-----
-
-重新运行应用。应该可以看到关于引擎启动与创建数据库表结构的提示日志:
-
-image::images/getting.started.console.logging2.png[align="center"]
-
-这样就得到了一个启动可用的流程引擎。接下来为它提供一个流程!
-
-[[_deploying_a_process_definition]]
-==== 部署流程定义
-
-我们要构建的流程是一个非常简单的请假流程。Flowable引擎需要流程定义为BPMN 2.0格式,这是一个业界广泛接受的XML标准。
-在Flowable术语中,我们将其称为一个**流程定义(process definition)**。一个__流程定义__可以启动多个**流程实例(process instance)**。__流程定义__可以看做是重复执行流程的蓝图。
-在这个例子中,__流程定义__定义了请假的各个步骤,而一个__流程实例__对应某个雇员提出的一个请假申请。
-
-BPMN 2.0存储为XML,并包含可视化的部分:使用标准方式定义了每个步骤类型(人工任务,自动服务调用,等等)如何呈现,以及如何互相连接。这样BPMN 2.0标准使技术人员与业务人员能用双方都能理解的方式交流业务流程。
-
-我们要使用的流程定义为:
-
-image::images/getting.started.bpmn.process.png[align="center"]
-
-这个流程应该已经十分自我解释了。但为了明确起见,说明一下几个要点:
-
-* 我们假定启动流程需要提供一些信息,例如雇员名字、请假时长以及说明。当然,这些可以单独建模为流程中的第一步。
-但是如果将它们作为流程的“输入信息”,就能保证只有在实际请求时才会建立一个流程实例。否则(将提交作为流程的第一步),用户可能在提交之前改变主意并取消,但流程实例已经创建了。
-在某些场景中,就可能影响重要的指标(例如启动了多少申请,但还未完成),取决于业务目标。
-* 左侧的圆圈叫做**启动事件(start event)**。这是一个流程实例的起点。
-* 第一个矩形是一个**用户任务(user task)**。这是流程中人类用户操作的步骤。在这个例子中,经理需要批准或驳回申请。
-* 取决于经理的决定,**排他网关(exclusive gateway)** (带叉的菱形)会将流程实例路由至批准或驳回路径。
-* 如果批准,则需要将申请注册至某个外部系统,并跟着另一个用户任务,将经理的决定通知给申请人。当然也可以改为发送邮件。
-* 如果驳回,则为雇员发送一封邮件通知他。
-
-
-一般来说,这样的__流程定义__使用可视化建模工具建立,如Flowable Designer(Eclipse)或Flowable Web Modeler(Web应用)。
-
-但在这里我们直接撰写XML,以熟悉BPMN 2.0及其概念。
-
-与上面展示的流程图对应的BPMN 2.0 XML在下面显示。请注意这只包含了“流程部分”。如果使用图形化建模工具,实际的XML文件还将包含“可视化部分”,用于描述图形信息,如流程定义中各个元素的坐标(所有的图形化信息包含在XML的__BPMNDiagram__标签中,作为__definitions__标签的子元素)。
-
-将下面的XML保存在__src/main/resources__文件夹下名为__holiday-request.bpmn20.xml__的文件中。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-第2至11行看起来挺吓人,但其实在大多数的流程定义中都是一样的。这是一种__样板文件__,需要与BPMN 2.0标准规范完全一致。
-
-每一个步骤(在BPMN 2.0术语中称作**'活动(activity)'**)都有一个__id__属性,为其提供一个在XML文件中唯一的标识符。所有的__活动__都可以设置一个名字,以提高流程图的可读性。
-
-__活动__之间通过**顺序流(sequence flow)**连接,在流程图中是一个有向箭头。在执行流程实例时,执行(execution)会从__启动事件__沿着__顺序流__流向下一个__活动__。
-
-离开__排他网关(带有X的菱形)__的__顺序流__很特别:都以__表达式(expression)__的形式定义了__条件(condition)__ (见第25至32行)。当流程实例的执行到达这个__网关__时,会计算__条件__,并使用第一个计算为__true__的顺序流。这就是__排他__的含义:只选择一个。当然如果需要不同的路由策略,可以使用其他类型的网关。
-
-这里用作条件的__表达式__为__${approved}__,这是__${approved == true}__的简写。变量'approved'被称作**流程变量(process variable)**。__流程变量__是持久化的数据,与流程实例存储在一起,并可以在流程实例的生命周期中使用。在这个例子里,我们需要在特定的地方(当经理用户任务提交时,或者以Flowable的术语来说,__完成(complete)__时)设置这个__流程变量__,因为这不是流程实例启动时就能获取的数据。
-
-现在我们已经有了流程BPMN 2.0 XML文件,下来需要将它**'部署(deploy)'**到引擎中。__部署__一个流程定义意味着:
-
-* 流程引擎会将XML文件存储在数据库中,这样可以在需要的时候获取它。
-* 流程定义转换为内部的、可执行的对象模型,这样使用它就可以启动__流程实例__。
-
-将流程定义__部署__至Flowable引擎,需要使用__RepositoryService__,其可以从__ProcessEngine__对象获取。使用__RepositoryService__,可以通过XML文件的路径创建一个新的__部署(Deployment)__,并调用__deploy()__方法实际执行:
-
-[source,java,linenums]
-----
-RepositoryService repositoryService = processEngine.getRepositoryService();
-Deployment deployment = repositoryService.createDeployment()
- .addClasspathResource("holiday-request.bpmn20.xml")
- .deploy();
-----
-
-我们现在可以通过API查询验证流程定义已经部署在引擎中(并学习一些API)。通过__RepositoryService__创建的__ProcessDefinitionQuery__对象实现。
-
-[source,java,linenums]
-----
-ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
- .deploymentId(deployment.getId())
- .singleResult();
-System.out.println("Found process definition : " + processDefinition.getName());
-----
-
-[[_starting_a_process_instance]]
-==== 启动流程实例
-
-现在已经在流程引擎中__部署__了流程定义,因此可以使用这个__流程定义__作为“蓝图”启动__流程实例__。
-
-要启动流程实例,需要提供一些初始化__流程变量__。一般来说,可以通过呈现给用户的表单,或者在流程由其他系统自动触发时通过REST API,来获取这些变量。在这个例子里,我们简化为使用java.util.Scanner类在命令行输入一些数据:
-
-[source,java,linenums]
-----
-Scanner scanner= new Scanner(System.in);
-
-System.out.println("Who are you?");
-String employee = scanner.nextLine();
-
-System.out.println("How many holidays do you want to request?");
-Integer nrOfHolidays = Integer.valueOf(scanner.nextLine());
-
-System.out.println("Why do you need them?");
-String description = scanner.nextLine();
-----
-
-接下来,我们使用__RuntimeService__启动一个__流程实例__。收集的数据作为一个__java.util.Map__实例传递,其中的键就是之后用于获取变量的标识符。这个流程实例使用__key__启动。这个__key__就是BPMN 2.0 XML文件中设置的__id__属性,在这个例子里是__holidayRequest__。
-
-(请注意:除了使用key之外,在后面你还会看到有很多其他方式启动一个流程实例)
-
-[source,xml]
-----
-
-----
-
-[source,java,linenums]
-----
-RuntimeService runtimeService = processEngine.getRuntimeService();
-
-Map variables = new HashMap();
-variables.put("employee", employee);
-variables.put("nrOfHolidays", nrOfHolidays);
-variables.put("description", description);
-ProcessInstance processInstance =
- runtimeService.startProcessInstanceByKey("holidayRequest", variables);
-----
-
-在流程实例启动后,会创建一个**执行(execution)**,并将其放在启动事件上。从这里开始,这个__执行__沿着顺序流移动到经理审批的用户任务,并执行用户任务行为。这个行为将在数据库中创建一个任务,该任务可以之后使用查询找到。用户任务是一个__等待状态(wait state)__,引擎会停止执行,返回API调用处。
-
-[[_sidetrack_transactionality]]
-==== 另一个话题:事务
-
-在Flowable中,数据库事务扮演了关键角色,用于保证数据一致性,并解决并发问题。当调用Flowable API时,默认情况下,所有操作都是同步的,并处于同一个事务下。这意味着,当方法调用返回时,会启动并提交一个事务。
-
-流程启动后,会有**一个数据库事务**从流程实例启动时持续到下一个__等待状态__。在这个例子里,指的是第一个用户任务。当引擎到达这个用户任务时,状态会持久化至数据库,提交事务,并返回API调用处。
-
-在Flowable中,当一个流程实例运行时,总会有一个数据库事务从前一个__等待状态__持续到下一个__等待状态__。数据持久化之后,可能在数据库中保存很长时间,甚至几年,直到某个API调用使流程实例继续执行。请注意当流程处在等待状态时,不会消耗任何计算或内存资源,直到下一次APi调用。
-
-在这个例子中,当第一个用户任务完成时,会启动一个数据库事务,从用户任务开始,经过排他网关(自动逻辑),直到第二个用户任务。或通过另一条路径直接到达结束。
-
-[[_querying_and_completing_tasks]]
-==== 查询与完成任务
-
-在更实际的应用中,会为雇员及经理提供用户界面,让他们可以登录并查看任务列表。其中可以看到作为__流程变量__存储的流程实例数据,并决定如何操作任务。在这个例子中,我们通过执行API调用来模拟任务列表,通常这些API都是由UI驱动的服务在后台调用的。
-
-我们还没有为用户任务配置办理人。我们想将第一个任务指派给"经理(managers)"组,而第二个用户任务指派给请假申请的提交人。因此需要为第一个任务添加__candidateGroups__属性:
-
-[source,xml]
-----
-
-----
-
-并如下所示为第二个任务添加__assignee__属性。请注意我们没有像上面的'managers'一样使用静态值,而是使用一个流程变量动态指派。这个流程变量是在流程实例启动时传递的:
-
-
-[source,xml]
-----
-
-----
-
-要获得实际的任务列表,需要通过__TaskService__创建一个__TaskQuery__。我们配置这个查询只返回'managers'组的任务:
-
-[source,java,linenums]
-----
-TaskService taskService = processEngine.getTaskService();
-List tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
-System.out.println("You have " + tasks.size() + " tasks:");
-for (int i=0; i processVariables = taskService.getVariables(task.getId());
-System.out.println(processVariables.get("employee") + " wants " +
- processVariables.get("nrOfHolidays") + " of holidays. Do you approve this?");
-----
-
-运行结果像下面这样:
-
-image::images/getting.started.console.logging3.png[align="center"]
-
-经理现在就可以**完成任务**了。在现实中,这通常意味着由用户提交一个表单。表单中的数据作为__流程变量__传递。在这里,我们在完成任务时传递带有'approved'变量(这个名字很重要,因为之后会在顺序流的条件中使用!)的map来模拟:
-
-[source,java,linenums]
-----
-boolean approved = scanner.nextLine().toLowerCase().equals("y");
-variables = new HashMap();
-variables.put("approved", approved);
-taskService.complete(task.getId(), variables);
-----
-
-现在任务完成,并会在离开排他网关的两条路径中,基于'approved'流程变量选择一条。
-
-[[getting.started.delegate]]
-==== 实现JavaDelegate
-
-拼图还缺了一块:我们还没有实现申请通过后执行的自动逻辑。在BPMN 2.0 XML中,这是一个**服务任务(service task)**:
-
-[source,xml]
-----
-
-----
-
-在现实中,这个逻辑可以做任何事情:向某个系统发起一个HTTP REST服务调用,或调用某个使用了好几十年的系统中的遗留代码。我们不会在这里实现实际的逻辑,而只是简单的日志记录__流程__。
-
-创建一个新的类(在Eclipse里__File -> New -> Class__),填入__org.flowable__作为包名,__CallExternalSystemDelegate__作为类名。让这个类实现__org.flowable.engine.delegate.JavaDelegate__接口,并实现__execute__方法:
-
-[source,java,linenums]
-----
-package org.flowable;
-
-import org.flowable.engine.delegate.DelegateExecution;
-import org.flowable.engine.delegate.JavaDelegate;
-
-public class CallExternalSystemDelegate implements JavaDelegate {
-
- public void execute(DelegateExecution execution) {
- System.out.println("Calling the external system for employee "
- + execution.getVariable("employee"));
- }
-
-}
-----
-
-当__执行__到达__服务任务__时,会初始化并调用BPMN 2.0 XML中所引用的类。
-
-现在执行这个例子的时候,就会显示出日志信息,说明已经执行了自定义逻辑:
-
-image::images/getting.started.console.logging4.png[align="center"]
-
-[[_working_with_historical_data]]
-==== 使用历史数据
-
-选择使用Flowable这样的流程引擎的原因之一,是它可以自动存储所有流程实例的**审计数据**或**历史数据**。这些数据可以用于创建报告,深入展现组织运行的情况,瓶颈在哪里,等等。
-
-例如,如果希望显示流程实例已经执行的时间,就可以从__ProcessEngine__获取__HistoryService__,并创建__历史活动(historical activities)__的查询。在下面的代码片段中,可以看到我们添加了一些额外的过滤条件:
-
-* 只选择一个特定流程实例的活动
-* 只选择已完成的活动
-
-结果按照结束时间排序,代表其执行顺序。
-
-[source,java,linenums]
-----
-HistoryService historyService = processEngine.getHistoryService();
-List activities =
- historyService.createHistoricActivityInstanceQuery()
- .processInstanceId(processInstance.getId())
- .finished()
- .orderByHistoricActivityInstanceEndTime().asc()
- .list();
-
-for (HistoricActivityInstance activity : activities) {
- System.out.println(activity.getActivityId() + " took "
- + activity.getDurationInMillis() + " milliseconds");
-}
-----
-
-再次运行例子,可以看到控制台中显示:
-
-----
-startEvent took 1 milliseconds
-approveTask took 2638 milliseconds
-decision took 3 milliseconds
-externalSystemCall took 1 milliseconds
-----
-
-[[_conclusion]]
-==== 小结
-
-这个教程介绍了很多Flowable与BPMN 2.0的概念与术语,也展示了如何编程使用Flowable API。
-
-当然,这只是个开始。下面的章节会更深入介绍许多Flowable引擎支持的选项与特性。其他章节介绍安装与使用Flowable引擎的不同方法,并详细介绍了所有可用的BPMN 2.0结构。
-
-[[getting.started.rest]]
-=== 开始使用Flowable REST API
-
-这个章节展示了与<>相同的例子:部署一个流程定义,启动一个流程实例,获取任务列表并完成一个任务。最好先快速浏览上一章节以了解所做的事情。
-
-这一次,将使用Flowable REST API而不是Java API。你很快就会意识到REST API与Java API紧密关联。只要了解一个,就能很快学会另一个。
-
-可以在<>章节找到Flowable REST API的完整细节。
-
-[[_setting_up_the_rest_application]]
-==== 安装REST应用
-
-从flowable.org网站下载.zip文件后,可以在__wars__文件夹下找到REST应用。要运行这个WAR文件,需要一个servlet容器,例如link:$$http://tomcat.apache.org/$$[Tomcat]、link:$$http://www.eclipse.org/jetty/$$[Jetty]等。
-
-使用Tomcat的步骤如下:
-
-* 下载并解压缩最新的Tomcat zip文件(在Tomcat网站中选择'Core'发行版)。
-* 将flowable-rest.war文件从解压的Flowable发行版的__wars__文件夹中复制到解压的Tomcat文件夹下的__webapps__文件夹下。
-* 使用命令行,转到Tomcat文件夹下的__bin__文件夹。
-* 执行'__./catalina run__'启动Tomcat服务器。
-
-在服务启动过程中,会显示一些Flowable日志信息。在最后显示的一条类似'__INFO [main] org.apache.catalina.startup.Catalina.start Server startup in xyz ms__'的消息标志着服务器已经启动,可以接受请求。请注意默认情况下,使用H2内存数据库,这意味着数据在服务器重启后会丢失。
-
-在下面的章节中,我们使用cURL展示各种REST调用。所有的REST调用默认都使用__基本认证__保护,所有的调用的用户都是 'rest-admin',密码为'test'。
-
-
-在启动后,通过执行下列命令验证应用运行正常:
-
-----
-curl --user rest-admin:test http://localhost:8080/flowable-rest/service/management/engine
-----
-
-如果能获得正确的json响应,则说明REST API已经启动并在工作。
-
-[[_deploying_a_process_definition_2]]
-==== 部署流程定义
-
-第一步是部署一个流程定义。使用REST API时,需要将一个.bpmn20.xml文件(或对于多个流程引擎,一个.zip文件)作为'multipart/formdata'上传:
-
-----
-curl --user rest-admin:test -F "file=@holiday-request.bpmn20.xml" http://localhost:8080/flowable-rest/service/repository/deployments
-----
-
-要验证流程定义已经正确部署,可以请求流程定义的列表:
-
-----
-curl --user rest-admin:test http://localhost:8080/flowable-rest/service/repository/process-definitions
-----
-
-这将返回当前引擎中部署的所有流程定义的列表。
-
-[[_start_a_process_instance]]
-==== 启动流程实例
-
-使用REST API启动一个流程实例与使用Java API很像:提供__key__作为流程定义的标识,并使用一个map作为初始化流程变量:
-
-----
-curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "processDefinitionKey":"holidayRequest", "variables": [ { "name":"employee", "value": "John Doe" }, { "name":"nrOfHolidays", "value": 7 }]}' http://localhost:8080/flowable-rest/service/runtime/process-instances
-----
-
-将返回:
-
-----
-{"id":"43","url":"http://localhost:8080/flowable-rest/service/runtime/process-instances/43","businessKey":null,"suspended":false,"ended":false,"processDefinitionId":"holidayRequest:1:42","processDefinitionUrl":"http://localhost:8080/flowable-rest/service/repository/process-definitions/holidayRequest:1:42","activityId":null,"variables":[],"tenantId":"","completed":false}
-----
-
-[[_task_list_and_completing_a_task]]
-==== 任务列表与完成任务
-
-当流程实例启动后,第一个任务会指派给'managers'组。要获取这个组的所有任务,可以通过REST API进行任务查询:
-
-----
-curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "candidateGroup" : "managers" }' http://localhost:8080/flowable-rest/service/query/tasks
-----
-
-这将返回'manager'组的所有任务的列表。
-
-可以这样完成任务:
-
-----
-curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "action" : "complete", "variables" : [ { "name" : "approved", "value" : true} ] }' http://localhost:8080/flowable-rest/service/runtime/tasks/25
-----
-
-然而,很可能会产生如下的错误:
-
-----
-{"message":"Internal server error","exception":"couldn't instantiate class org.flowable.CallExternalSystemDelegate"}
-----
-
-这意味着引擎无法找到服务任务引用的__CallExternalSystemDelegate__类。要解决这个错误,需要将该类放在应用的classpath下(并需要重启应用)。按照<>的介绍创建该类,并将其打包为JAR,放在Tomcat的__webapps__目录下的flowable-rest目录下的__WEB-INF/lib__目录下。
diff --git a/docs/userguide/src/zh_CN/bpmn/ch03-Configuration.adoc b/docs/userguide/src/zh_CN/bpmn/ch03-Configuration.adoc
deleted file mode 100755
index 3f4da310a51..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch03-Configuration.adoc
+++ /dev/null
@@ -1,801 +0,0 @@
-[[_configuration]]
-== 配置
-
-[[configuration]]
-
-=== 创建ProcessEngine
-
-Flowable流程引擎通过名为++flowable.cfg.xml++的XML文件进行配置。请注意这种方式与<>**不**一样。
-
-获取++ProcessEngine++,最简单的方式是使用++org.flowable.engine.ProcessEngines++类:
-
-[source,java,linenums]
-----
-ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine()
-----
-
-这样会从classpath寻找++flowable.cfg.xml++,并用这个文件中的配置构造引擎。下面的代码展示了一个配置的例子。后续章节会对配置参数进行详细介绍。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-请注意这个配置XML文件实际上是一个Spring配置文件。**但这并不意味着Flowable只能用于Spring环境!**我们只是利用Spring内部的解析与依赖注入功能来简化引擎的构建过程。
-
-也可以通过编程方式使用配置文件,来构造ProcessEngineConfiguration对象。也可以使用不同的bean id(例如第3行)。
-
-[source,java,linenums]
-----
-ProcessEngineConfiguration.
- createProcessEngineConfigurationFromResourceDefault();
- createProcessEngineConfigurationFromResource(String resource);
- createProcessEngineConfigurationFromResource(String resource, String beanName);
- createProcessEngineConfigurationFromInputStream(InputStream inputStream);
- createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName);
-----
-
-也可以不使用配置文件,使用默认配置(参考<>获得更多信息)。
-
-
-[source,java,linenums]
-----
-ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
-ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
-----
-
-所有的++ProcessEngineConfiguration.createXXX()++方法都返回++ProcessEngineConfiguration++,并可以继续按需调整。调用++buildProcessEngine()++后,生成一个++ProcessEngine++:
-
-[source,java,linenums]
-----
-ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()
- .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE)
- .setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000")
- .setAsyncExecutorActivate(false)
- .buildProcessEngine();
-----
-
-
-
-[[configurationRoot]]
-
-
-=== ProcessEngineConfiguration bean
-
-
-++flowable.cfg.xml++文件中必须包含一个id为$$'processEngineConfiguration'$$的bean。
-
-[source,xml,linenums]
-----
-
-----
-
-
-这个bean用于构建++ProcessEngine++。有多个类可以用于定义++processEngineConfiguration++。这些类用于不同的环境,并各自设置一些默认值。最佳实践是选择最匹配你环境的类,以便减少配置引擎需要的参数。目前可以使用的类为:[[configurationClasses]]
-
-* *org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration*:流程引擎独立运行。Flowable自行处理事务。在默认情况下,数据库检查只在引擎启动时进行(如果Flowable表结构不存在或表结构版本不对,会抛出异常)。
-* *org.flowable.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration*:这是一个便于使用单元测试的类。Flowable自行处理事务。默认使用H2内存数据库。数据库会在引擎启动时创建,并在引擎关闭时删除。使用这个类时,很可能不需要更多的配置(除了使用任务执行器或邮件等功能时)。
-* *org.flowable.spring.SpringProcessEngineConfiguration*:在流程引擎处于Spring环境时使用。查看<>章节了解更多信息。
-* *org.flowable.engine.impl.cfg.JtaProcessEngineConfiguration*:用于引擎独立运行,并使用JTA事务的情况。
-
-
-[[databaseConfiguration]]
-
-=== 配置数据库
-
-
-有两种方式配置Flowable引擎使用的数据库。第一种方式是定义数据库的JDBC参数:
-
-* *jdbcUrl*: 数据库的JDBC URL。
-* *jdbcDriver*: 对应数据库类型的驱动。
-* *jdbcUsername*: 用于连接数据库的用户名。
-* *jdbcPassword*: 用于连接数据库的密码。
-
-通过提供的JDBC参数构造的数据源,使用默认的link:$$http://www.mybatis.org/$$[MyBatis]连接池设置。可用下列属性调整这个连接池(来自MyBatis文档):
-
-* *jdbcMaxActiveConnections*: 连接池能够容纳的最大活动连接数量。默认值为10.
-* *jdbcMaxIdleConnections*: 连接池能够容纳的最大空闲连接数量。
-* *jdbcMaxCheckoutTime*: 连接从连接池“取出”后,被强制返回前的最大时间间隔,单位为毫秒。默认值为20000(20秒)。
-* *jdbcMaxWaitTime*: 这是一个底层设置,在连接池获取连接的时间异常长时,打印日志并尝试重新获取连接(避免连接池配置错误,导致没有异常提示)。默认值为20000(20秒)。
-
-数据库配置示例:
-
-[source,xml,linenums]
-----
-
-
-
-
-----
-
-我们的跑分显示MyBatis连接池在处理大量并发请求时,并不是最经济或最具弹性的。因此,建议使用++javax.sql.DataSource++的实现,并将其注入到流程引擎配置中(如Hikari、Tomcat JDBC连接池,等等):
-
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
- ...
-
-----
-
-
-请注意Flowable发布时不包括用于定义数据源的库。需要自行把库放在classpath中。
-
-无论使用JDBC还是数据源方式配置,都可以使用下列参数:
-
-* *databaseType*: 通常不需要专门设置这个参数,因为它可以从数据库连接信息中自动检测得出。只有在自动检测失败时才需要设置。可用值:{h2, mysql, oracle, postgres, mssql, db2}。这个选项会决定创建、删除与查询时使用的脚本。查看<>章节了解我们支持哪些类型的数据库。
-* *databaseSchemaUpdate*: 用于设置流程引擎启动关闭时使用的数据库表结构控制策略。
-** +false+ (默认): 当引擎启动时,检查数据库表结构的版本是否匹配库文件版本。版本不匹配时抛出异常。
-** ++true++: 构建引擎时,检查并在需要时更新表结构。表结构不存在则会创建。
-** ++create-drop++: 引擎创建时创建表结构,并在引擎关闭时删除表结构。
-
-[[jndiDatasourceConfig]]
-
-=== 配置JNDI数据源
-
-默认情况下,Flowable的数据库配置保存在每个web应用WEB-INF/classes文件夹下的db.properties文件中。有时这样并不合适,因为这需要用户修改Flowable源码中的db.properties文件并重新编译war包,或者在部署后解开war包并修改db.properties文件。
-
-
-通过使用JNDI(Java Naming and Directory Interface,Java命名和目录接口)获取数据库连接,连接就完全交由Servlet容器管理,并可以在WAR部署之外管理配置。同时也提供了比db.properties中更多的控制连接的参数。
-
-[[jndi_configuration]]
-
-==== 配置
-
-根据你使用的servlet容器应用不同,配置JNDI数据源的方式也不同。下面的介绍用于Tomcat,对于其他容器应用,请参考对应的文档。
-
-Tomcat的JNDI资源配置在$CATALINA_BASE/conf/[enginename]/[hostname]/[warname].xml (对于Flowable UI通常会是$CATALINA_BASE/conf/Catalina/localhost/flowable-app.xml)。当应用第一次部署时,默认会从Flowable war包中复制context.xml。所以如果存在这个文件则需要替换。例如,如果需要将JNDI资源修改为应用连接MySQL而不是H2,需要如下修改:
-
-
-[source,xml,linenums]
-----
-
-
-
-
-----
-
-[[_jndi_properties]]
-==== JNDI参数
-
-在Flowable UI的配置文件中使用下列参数配置JNDI数据源:
-
-* spring.datasource.jndi-name=: 数据源的JNDI名
-* datasource.jndi.resourceRef: 设置是否在J2EE容器中查找。也就是说,如果JNDI名中没有包含"java:comp/env/"前缀,是否需要添加它。默认为"true"。
-
-
-[[supporteddatabases]]
-
-
-=== 支持的数据库
-
-下面列出Flowable用于引用数据库的类型(区分大小写!)。
-
-[[databaseTypes]]
-[options="header"]
-|===============
-|Flowable数据库类型|示例JDBC URL|备注
-|h2|jdbc:h2:tcp://localhost/flowable|默认配置的数据库
-|mysql|jdbc:mysql://localhost:3306/flowable?autoReconnect=true|已使用mysql-connector-java数据库驱动测试
-|oracle|jdbc:oracle:thin:@localhost:1521:xe|
-|postgres|jdbc:postgresql://localhost:5432/flowable|
-|db2|jdbc:db2://localhost:50000/flowable|
-|mssql|jdbc:sqlserver://localhost:1433;databaseName=flowable (jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver) _OR_ jdbc:jtds:sqlserver://localhost:1433/flowable (jdbc.driver=net.sourceforge.jtds.jdbc.Driver)|已使用Microsoft JDBC Driver 4.0 (sqljdbc4.jar)与JTDS Driver测试
-|===============
-
-
-[[creatingDatabaseTable]]
-
-=== 创建数据库表
-
-在你的数据库中创建数据库表,最简单的方法是:
-
-* 在classpath中添加flowable-engine JAR
-* 添加合适的数据库驱动
-* 在classpath中添加Flowable配置文件(__flowable.cfg.xml__),指向你的数据库(参考<>)
-* 执行__DbSchemaCreate__类的main方法
-
-然而,通常只有数据库管理员可以在数据库中执行DDL语句,在生产环境中这也是最明智的选择。DDL的SQL脚本可以在Flowable下载页面或Flowable发布文件夹中找到,位于++database++子文件夹。引擎JAR (__flowable-engine-x.jar__)的__org/flowable/db/create__包中也有一份(__drop__文件夹存放删除脚本)。SQL文件的格式为:
-
-----
-flowable.{db}.{create|drop}.{type}.sql
-----
-
-其中__db__为<>,而__type__为:
-
-* *engine:* 引擎执行所需的表,必需。
-* *history:* 存储历史与审计信息的表。当历史级别设置为__none__时不需要。请注意不使用这些表会导致部分使用历史数据的功能失效(如任务备注)。
-
-**MySQL用户请注意:**低于5.6.4的MySQL版本不支持timestamps或包含毫秒精度的日期。更糟的是部分版本会在创建类似的列时抛出异常,而另一些版本则不会。当使用自动创建/升级时,引擎在执行时会自动修改DDL语句。当使用DDL文件方式建表时,可以使用通用版本,或使用文件名包含__mysql55__的特殊版本(用于5.6.4以下的任何版本)。特殊版本的文件中不会使用毫秒精度的列类型。
-
-具体地说,对于MySQL的版本:
-
-* *<5.6:* 不支持毫秒精度。可以使用DDL文件(使用包含__mysql55__的文件)。可以使用自动创建/升级。
-* *5.6.0 - 5.6.3:* 不支持毫秒精度。**不**可以使用自动创建/升级。建议升级为较新版本的数据库。如果确实需要,可以使用包含__mysql55__的DDL文件。
-* *5.6.4+:* 支持毫秒精度。可以使用DDL文件(默认的包含__mysql__的文件)。可以使用自动创建/升级。
-
-
-请注意如果在Flowable表已经创建/升级后,再升级MySQL数据库,则需要手工修改列类型!
-
-
-[[database.tables.explained]]
-
-
-=== 数据库表名说明
-
-Flowable的所有数据库表都以**ACT_**开头。第二部分是说明表用途的两字符标示符。服务API的命名也大略符合这个规则。
-
-* *ACT_RE_**: 'RE'代表++repository++。带有这个前缀的表包含“静态”信息,例如流程定义与流程资源(图片、规则等)。
-* *ACT_RU_**: 'RU'代表++runtime++。这些表存储运行时信息,例如流程实例(process instance)、用户任务(user task)、变量(variable)、作业(job)等。Flowable只在流程实例运行中保存运行时数据,并在流程实例结束时删除记录。这样保证运行时表小和快。
-* *ACT_HI_**: 'HI'代表++history++。这些表存储历史数据,例如已完成的流程实例、变量、任务等。
-* *ACT_GE_**: 通用数据。在多处使用。
-
-
-[[databaseUpgrade]]
-
-
-=== 数据库升级
-
-在升级前,请确保你已经(使用数据库的备份功能)备份了数据库。
-
-默认情况下,每次流程引擎创建时会进行版本检查,通常是在你的应用或者Flowable web应用启动的时候。如果Flowable发现库版本与Flowable数据库表版本不同,会抛出异常。
-
-要进行升级,首先需要将下列配置参数放入你的flowable.cfg.xml配置文件:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-----
-
-**同时,在classpath中加上合适的数据库驱动。**升级应用中的Flowable库,或者启动一个新版本的Flowable,并将它指向包含旧版本数据的数据库。将++databaseSchemaUpdate++设置为++true++。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
-
-**也可以直接运行升级DDL语句。**也可以从Flowable下载页面获取升级数据库脚本并运行。
-
-[[jobExecutorConfiguration]]
-
-=== 作业执行器(从6.0.1版本起)
-
-在Flowable V6中唯一可用的作业执行器,是Flowable V5中的异步执行器(async executor)。因为它为Flowable引擎提供了性能更好,对数据库也更友好的执行异步作业的方式。
-Flowable V5中的作业执行器(job executor)在V6中不再可用。可以在用户手册的高级章节找到更多信息。
-
-此外,如果在Java EE 7下运行,容器还可以使用符合JSR-236标准的++ManagedAsyncJobExecutor++来管理线程。要启用这个功能,需要在配置中如下加入线程工厂:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-----
-
-如果没有设置线程工厂,ManagedAsyncJobExecutor实现会退化为默认实现(AsyncJobExecutor)。
-
-[[_job_executor_activation]]
-=== 启用作业执行器
-
-++AsyncExecutor++是管理线程池的组件,用于触发定时器与其他异步任务。也可以使用其他实现(如使用消息队列,参见用户手册的高级章节)。
-
-默认情况下,++AsyncExecutor++并未启用,也不会启动。如下配置使异步执行器与Flowable引擎一同启动:
-
-[source,xml,linenums]
-----
-
-----
-
-asyncExecutorActivate这个参数使Flowable引擎在启动同时启动异步执行器。
-
-[[mailServerConfiguration]]
-
-
-=== 配置邮件服务器
-
-配置邮件服务器是可选的。Flowable支持在业务流程中发送电子邮件。发送电子邮件需要配置有效的SMTP邮件服务器。查看<>了解配置选项。
-
-
-[[historyConfiguration]]
-
-
-=== 配置历史
-
-历史存储的配置是可选的。你可以通过调整配置控制<>。查看<>章节了解更多细节。
-
-[source,xml,linenums]
-----
-
-----
-
-
-[[asyncHistoryConfiguration]]
-
-
-=== 配置异步历史
-
-[实验性] 从Flowable 6.1.0起,添加了异步历史功能。当启用异步历史时,历史数据将由历史任务执行器负责持久化,而不是与运行时执行持久化同步保存。
-查看<>章节了解更多细节。
-
-[source,xml,linenums]
-----
-
-----
-
-
-[[exposingConfigurationBeans]]
-
-
-=== 配置在表达式与脚本中可用的bean
-
-默认情况下,所有通过++flowable.cfg.xml++或你自己的Spring配置文件声明的bean,都可以在表达式与脚本中使用。如果你希望限制配置文件中bean的可见性,可以使用流程引擎配置的++beans++参数。++ProcessEngineConfiguration++中的++beans++参数是一个map。当你配置这个参数时,只有在这个map中声明的bean可以在表达式与脚本中使用。bean会使用你在map中指定的名字暴露。
-
-
-[[processDefinitionCacheConfiguration]]
-
-
-=== 配置部署缓存
-
-鉴于流程定义信息不会改变,为了避免每次使用流程定义时都读取数据库,所有的流程定义都会(在解析后)被缓存。默认情况下,这个缓存没有限制。要限制流程定义缓存,加上如下的参数
-
-[source,xml,linenums]
-----
-
-----
-
-
-设置这个参数,会将默认的hashmap缓存替换为LRU缓存,以进行限制。当然,参数的“最佳”取值,取决于总的流程定义数量,以及实际使用的流程定义数量。
-
-
-也可以注入自己的缓存实现。必须是一个实现了++org.flowable.engine.impl.persistence.deploy.DeploymentCache++接口的bean:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-类似的,可以使用名为++knowledgeBaseCacheLimit++与++knowledgeBaseCache++的参数配置规则缓存(rules cache)。只有在流程中使用规则任务(rules task)时才需要设置。
-
-
-[[loggingConfiguration]]
-
-
-=== 日志
-
-所有的日志(Flowable、Spring、MyBatis等)都通过SLF4J路由,并允许你自行选择日志实现。
-
-**默认情况下,Flowable引擎依赖中不提供SFL4J绑定JAR。你需要自行将其加入你的项目,以便使用所选的日志框架。**如果没有加入实现JAR,SLF4J会使用NOP-logger。这时除了一条警告外,不会记录任何日志。可以从link:$$http://www.slf4j.org/codes.html#StaticLoggerBinder$$[http://www.slf4j.org/codes.html#StaticLoggerBinder]了解关于绑定的更多信息。
-
-可以像这样(这里使用Log4j)使用Maven添加依赖,请注意你还需要加上版本:
-
-[source,xml,linenums]
-----
-
- org.slf4j
- slf4j-log4j12
-
-----
-
-
-Flowable-UI与Flowable-rest web应用配置为使用Log4j绑定。运行所有flowable-*模块的测试时也会使用Log4j。
-
-**重要提示:当使用classpath中带有commons-logging的容器时:**为了将spring的日志路由至SLF4j,需要使用桥接(参考link:$$http://www.slf4j.org/legacy.html#jclOverSLF4J$$[http://www.slf4j.org/legacy.html#jclOverSLF4J])。如果你的容器提供了commons-logging实现,请按照link:$$http://www.slf4j.org/codes.html#release$$[http://www.slf4j.org/codes.html#release]页面的指示调整。
-
-
-使用Maven的示例(省略了版本):
-
-[source,xml,linenums]
-----
-
- org.slf4j
- jcl-over-slf4j
-
-----
-
-
-[[MDC]]
-
-
-=== 映射诊断上下文
-
-
-Flowable支持SLF4J的映射诊断上下文特性。下列基本信息会与需要日志记录的信息一起,传递给底层日志实现:
-
-* processDefinition Id 作为 mdcProcessDefinitionID
-* processInstance Id 作为 mdcProcessInstanceID
-* execution Id 作为 mdcExecutionId
-
-默认情况下这些信息都不会被日志记录,但可以通过配置logger,按照你想要的格式,与其他日志信息一起显示。例如在Log4j中进行如下简单的格式定义,就可以让logger显示上述信息:
-
-[source,properties,linenums]
-----
-log4j.appender.consoleAppender.layout.ConversionPattern=ProcessDefinitionId=%X{mdcProcessDefinitionID}
-executionId=%X{mdcExecutionId} mdcProcessInstanceID=%X{mdcProcessInstanceID} mdcBusinessKey=%X{mdcBusinessKey} %m%n
-----
-
-如果需要使用日志中包含的信息进行实时监测(如使用日志分析器),就会很有帮助。
-
-
-[[eventDispatcher]]
-
-
-=== 事件处理器
-
-Flowable引擎中的事件机制可以让你在引擎中发生多种事件的时候得到通知。查看<>了解可用的事件。
-
-可以只为特定种类的事件注册监听器,而不是在任何类型的事件发送时都被通知。可以<>添加引擎全局的事件监听器,<>添加引擎全局的事件监听器,也可以<>添加事件监听器。
-
-所有被分发的事件都是++org.flowable.engine.common.api.delegate.event.FlowableEvent++的子类。事件(在可用时)提供++type++, +executionId+, ++processInstanceId++与++processDefinitionId++。部分事件含有关于发生事件的上下文信息。关于事件包含的附加信息,请参阅<>。
-
-[[eventDispatcherListener]]
-
-
-==== 实现事件监听器
-
-对事件监听器的唯一要求,是要实现++org.flowable.engine.delegate.event.FlowableEventListener++接口。下面是一个监听器实现的例子,它将接收的所有事件打印至标准输出,并对作业执行相关的事件特别处理:
-
-[source,java,linenums]
-----
-public class MyEventListener implements FlowableEventListener {
-
- @Override
- public void onEvent(FlowableEvent event) {
- switch (event.getType()) {
-
- case JOB_EXECUTION_SUCCESS:
- System.out.println("A job well done!");
- break;
-
- case JOB_EXECUTION_FAILURE:
- System.out.println("A job has failed...");
- break;
-
- default:
- System.out.println("Event received: " + event.getType());
- }
- }
-
- @Override
- public boolean isFailOnException() {
- // onEvent方法中的逻辑并不重要,可以忽略日志失败异常……
-
- return false;
- }
-}
-----
-
-
-++isFailOnException()++方法决定了当事件分发后,++onEvent(..)++方法抛出异常时的行为。若返回++false++,忽略异常;若返回++true++,异常不会被忽略而会被上抛,使当前执行的命令失败。如果事件是API调用(或其他事务操作,例如作业执行)的一部分,事务将被回滚。如果事件监听器中并不是重要的业务操作,建议返回++false++。
-
-Flowable提供了少量基础实现,以简化常用的事件监听器使用场景。它们可以被用作监听器的示例或基类:
-
-* *org.flowable.engine.delegate.event.BaseEntityEventListener*: 事件监听器基类,可用来监听实体(entity)相关事件,特定或所有实体的事件都可以。它隐藏了类型检测,提供了4个需要覆盖的方法:++onCreate(..)++, ++onUpdate(..)++与++onDelete(..)++在实体创建、更新及删除时调用;对所有其他实体相关事件,++onEntityEvent(..)++会被调用。
-
-
-
-[[eventDispatcherConfiguration]]
-
-
-==== 配置与使用
-
-在流程引擎中配置的事件监听器会在流程引擎启动时生效,引擎重启后也会保持有效。
-
-++eventListeners++参数为++org.flowable.engine.delegate.event.FlowableEventListener++类实例的列表(list)。与其他地方一样,你可以声明内联bean定义,也可以用++ref++指向已有的bean。下面的代码片段在配置中添加了一个事件监听器,无论任何类型的事件分发时,都会得到通知:
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-
-
-
-----
-
-要在特定类型的事件分发时得到通知,使用++typedEventListeners++参数,值为map。map的key为逗号分隔的事件名字列表(或者一个事件的名字),取值为++org.flowable.engine.delegate.event.FlowableEventListener++实例的列表。下面的代码片段在配置中添加了一个事件监听器,它会在作业执行成功或失败时得到通知:
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-
-----
-
-
-事件分发的顺序由加入监听器的顺序决定。首先,所有普通(++eventListeners++参数定义的)事件监听器按照在++list++里的顺序被调用;之后,如果分发的是某类型的事件,则(++typedEventListeners++ 参数定义的)该类型监听器被调用。
-
-
-[[eventDispatcherConfigurationRuntime]]
-
-==== 在运行时添加监听器
-
-可以使用API(++RuntimeService++)为引擎添加或删除事件监听器:
-
-[source,java,linenums]
-----
-
-/**
- * 新增一个监听器,会在所有事件发生时被通知。
- * @param listenerToAdd 要新增的监听器
- */
-void addEventListener(FlowableEventListener listenerToAdd);
-
-/**
- * 新增一个监听器,在给定类型的事件发生时被通知。
- * @param listenerToAdd 要新增的监听器
- * @param types 监听器需要监听的事件类型
- */
-void addEventListener(FlowableEventListener listenerToAdd, FlowableEventType... types);
-
-/**
- * 从分发器中移除指定监听器。该监听器将不再被通知,无论该监听器注册为监听何种类型。
- * @param listenerToRemove 要移除的监听器
- */
- void removeEventListener(FlowableEventListener listenerToRemove);
-----
-
-请注意,运行时新增的监听器**在引擎重启后不会保持。**
-
-
-[[eventDispatcherConfigurationProcessDefinition]]
-
-
-==== 为流程定义增加监听器
-
-可以为某一流程定义增加监听器。只有与该流程定义相关,或使用该流程定义启动的流程实例相关的事件,才会调用这个监听器。监听器实现可以用完全限定类名(fully qualified classname)定义;也可以定义为表达式,该表达式需要能被解析为实现监听器接口的bean;也可以配置为抛出消息(message)/信号(signal)/错误(error)的BPMN事件。
-
-
-[[_listeners_executing_user_defined_logic]]
-===== 执行用户定义逻辑的监听器
-
-下面的代码片段为流程定义增加了2个监听器。第一个监听器接收任何类型的事件,使用完全限定类名定义。第二个监听器只在作业成功执行或失败时被通知,使用流程引擎配置中++beans++参数定义的bean作为监听器。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
- ...
-
-
-----
-
-实体相关的事件也可以在流程定义中增加监听器,只有在特定实体类型的事件发生时得到通知。下面的代码片段展示了如何设置。可以响应实体的所有事件(第一个例子),或只响应实体的特定类型事件(第二个例子)。
-
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
- ...
-
-
-----
-
-++entityType++可用的值有:++attachment++(附件), ++comment++(备注), ++execution++(执行), ++identity-link++(身份关联), ++job++(作业), ++process-instance++(流程实例), ++process-definition++(流程定义), ++task++(任务)。
-
-[[_listeners_throwing_bpmn_events]]
-
-===== 抛出BPMN事件的监听器
-
-处理分发的事件的另一个方法,是抛出BPMN事件。请牢记在心,只有特定种类的Flowable事件类型,抛出BPMN事件才合理。例如,在流程实例被删除时抛出BPMN事件,会导致错误。下面的代码片段展示了如何在流程实例中抛出信号,向外部流程(全局)抛出信号,在流程实例中抛出消息事件,以及在流程实例中抛出错误事件。这里不使用++class++或++delegateExpression++,而要使用++throwEvent++属性,以及一个附加属性,用于指定需要抛出的事件类型。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-如果需要使用额外的逻辑判断是否需要抛出BPMN事件,可以扩展Flowable提供的监听器类。通过在你的子类中覆盖++isValidEvent(FlowableEvent event)++,可以阻止抛出BPMN事件。相关的类为++org.flowable.engine.test.api.event.SignalThrowingEventListenerTest++, ++org.flowable.engine.impl.bpmn.helper.MessageThrowingEventListener++与++org.flowable.engine.impl.bpmn.helper.ErrorThrowingEventListener++.
-
-[[_notes_on_listeners_on_a_process_definition]]
-===== 关于流程定义监听器的说明
-
-* 事件监听器只能作为++extensionElements++的子元素,声明在++process++元素上。不能在个别节点(activity)上定义(事件)监听器。
-* ++delegateExpression++中的表达式,与其他表达式(例如在网关中的)不一样,不可以访问执行上下文。只能够引用在流程引擎配置中++beans++参数定义的bean;或是在使用spring(且没有定义beans参数)时,引用任何实现了监听器接口的spring bean。
-* 使用监听器的++class++属性时,只会创建唯一一个该类的实例。请确保监听器实现不依赖于成员变量,或确保多线程/上下文的使用安全。
-* 如果++events++属性使用了不合法的事件类型,或者使用了不合法的++throwEvent++值,会在流程定义部署时抛出异常(导致部署失败)。如果++class++或++delegateExecution++指定了不合法的值(不存在的类,不存在的bean引用,或者代理类没有实现监听器接口),在流程启动(或该流程定义的第一个有效事件分发给这个监听器)时,会抛出异常。请确保引用的类在classpath中,并且保证表达式能够解析为有效的实例。
-
-
-[[eventDispatcherCustomEvents]]
-
-==== 通过API分发事件
-
-
-可以通过API提供事件分发机制,向任何在引擎中注册的监听器分发自定义事件。建议(但不强制)只分发++CUSTOM++类型的++FlowableEvents++。使用++RuntimeService++分发事件:
-
-[source,java,linenums]
-----
-
-/**
- * 将给定事件分发给所有注册监听器。
- * @param event 要分发的事件。
- *
- * @throws FlowableException 当分发事件发生异常,或者{@link FlowableEventDispatcher}被禁用。
- * @throws FlowableIllegalArgumentException 当给定事件不可分发
- */
- void dispatchEvent(FlowableEvent event);
-----
-
-[[eventDispatcherEventTypes]]
-
-
-==== 支持的事件类型
-
-下表列出引擎中的所有事件类型。每种类型对应++org.flowable.engine.common.api.delegate.event.FlowableEventType++中的一个枚举值。
-
-
-[[eventTypes]]
-.Supported events
-[options="header"]
-|===============
-|事件名称|说明|事件类
-|ENGINE_CREATED|本监听器所属的流程引擎已经创建,并可以响应API调用。|+org.flowable...FlowableEvent+
-|ENGINE_CLOSED|本监听器所属的流程引擎已经关闭,不能再对该引擎进行API调用。|+org.flowable...FlowableEvent+
-|ENTITY_CREATED|新的实体已经创建。该实体包含在本事件里。|+org.flowable...FlowableEntityEvent+
-|ENTITY_INITIALIZED|新的实体已经创建并完全初始化。如果任何子实体作为该实体的一部分被创建,本事件会在子实体创建/初始化后触发,与 +$$ENTITY_CREATE$$+ 事件相反。|+org.flowable...FlowableEntityEvent+
-|ENTITY_UPDATED|实体已经更新。该实体包含在本事件里。|+org.flowable...FlowableEntityEvent+
-|ENTITY_DELETED|实体已经删除。该实体包含在本事件里。|+org.flowable...FlowableEntityEvent+
-|ENTITY_SUSPENDED|实体已经暂停。该实体包含在本事件里。ProcessDefinitions(流程定义), ProcessInstances(流程实例)与Tasks(任务)会分发本事件。|+org.flowable...FlowableEntityEvent+
-|ENTITY_ACTIVATED|实体已经激活。该实体包含在本事件里。ProcessDefinitions, ProcessInstances与Tasks会分发本事件。|+org.flowable...FlowableEntityEvent+
-|JOB_EXECUTION_SUCCESS|作业已经成功执行。该作业包含在本事件里。|+org.flowable...FlowableEntityEvent+
-|JOB_EXECUTION_FAILURE|作业执行失败。该作业与异常包含在本事件里。|+org.flowable...FlowableEntityEvent+ 及 +org.flowable...FlowableExceptionEvent+
-|JOB_RETRIES_DECREMENTED|作业重试次数已经由于执行失败而减少。该作业包含在本事件里。|+org.flowable...FlowableEntityEvent+
-|TIMER_SCHEDULED|已创建一个定时作业,并预计在未来时间点执行。|+org.flowable...FlowableEntityEvent+
-|TIMER_FIRED|定时器已经触发。|+org.flowable...FlowableEntityEvent+
-|JOB_CANCELED|作业已经取消。该作业包含在本事件里。作业会由于API调用取消,任务完成导致关联的边界定时器取消,也会由于新流程定义的部署而取消。|+org.flowable...FlowableEntityEvent+
-|ACTIVITY_STARTED|节点开始执行|+org.flowable...FlowableActivityEvent+
-|ACTIVITY_COMPLETED|节点成功完成|+org.flowable...FlowableActivityEvent+
-|ACTIVITY_CANCELLED|节点将要取消。节点的取消有三个原因(MessageEventSubscriptionEntity, SignalEventSubscriptionEntity, TimerEntity)。|+org.flowable...FlowableActivityCancelledEvent+
-|ACTIVITY_SIGNALED|节点收到了一个信号|+org.flowable...FlowableSignalEvent+
-|ACTIVITY_MESSAGE_RECEIVED|节点收到了一个消息。事件在节点接收消息前分发。节点接收消息后,会为该节点分发 +$$ACTIVITY_SIGNAL$$+ 或 +$$ACTIVITY_STARTED$$+ 事件,取决于其类型(边界事件,或子流程启动事件)。|+org.flowable...FlowableMessageEvent+
-|ACTIVITY_MESSAGE_WAITING|一个节点已经创建了一个消息事件订阅,并正在等待接收消息。|+org.flowable...FlowableMessageEvent+
-|ACTIVITY_MESSAGE_CANCELLED|一个节点已经取消了一个消息事件订阅,因此接收这个消息不会再触发该节点。|+org.flowable...FlowableMessageEvent+
-|ACTIVITY_ERROR_RECEIVED|节点收到了错误事件。在节点实际处理错误前分发。该事件的++activityId++为处理错误的节点。如果错误成功传递,后续会为节点发送 +$$ACTIVITY_SIGNALLED$$+ 或 +$$ACTIVITY_COMPLETE$$+ 消息。|+org.flowable...FlowableErrorEvent+
-|UNCAUGHT_BPMN_ERROR|抛出了未捕获的BPMN错误。流程没有该错误的处理器。该事件的++activityId++为空。|+org.flowable...FlowableErrorEvent+
-|ACTIVITY_COMPENSATE|节点将要被补偿(compensate)。该事件包含将要执行补偿的节点id。|+org.flowable...FlowableActivityEvent+
-|MULTI_INSTANCE_ACTIVITY_STARTED|多实例节点开始执行|+org.flowable...FlowableMultiInstanceActivityEvent+
-|MULTI_INSTANCE_ACTIVITY_COMPLETED|多实例节点成功完成|+org.flowable...FlowableMultiInstanceActivityEvent+
-|MULTI_INSTANCE_ACTIVITY_CANCELLED|多实例节点将要取消。多实例节点的取消有三个原因(MessageEventSubscriptionEntity, SignalEventSubscriptionEntity, TimerEntity)。|+org.flowable...FlowableMultiInstanceActivityCancelledEvent+
-|VARIABLE_CREATED|流程变量已经创建。本事件包含变量名、取值,及关联的执行和任务(若有)。|+org.flowable...FlowableVariableEvent+
-|VARIABLE_UPDATED|变量已经更新。本事件包含变量名、取值,及关联的执行和任务(若有)。|+org.flowable...FlowableVariableEvent+
-|VARIABLE_DELETED|变量已经删除。本事件包含变量名、最后取值,及关联的执行和任务(若有)。|+org.flowable...FlowableVariableEvent+
-|TASK_ASSIGNED|任务已经分派给了用户。该任务包含在本事件里。|+org.flowable...FlowableEntityEvent+
-|TASK_CREATED|任务已经创建。本事件在 +$$ENTITY_CREATE$$+ 事件之后分发。若该任务是流程的一部分,本事件会在任务监听器执行前触发。|+org.flowable...FlowableEntityEvent+
-|TASK_COMPLETED|任务已经完成。本事件在 +$$ENTITY_DELETE$$+ 事件前分发。若该任务是流程的一部分,本事件会在流程前进之前触发,并且会跟随一个 +$$ACTIVITY_COMPLETE$$+ 事件,指向代表该任务的节点。|+org.flowable...FlowableEntityEvent+
-|PROCESS_CREATED|流程实例已经创建。已经设置所有的基础参数,但还未设置变量。|+org.flowable...FlowableEntityEvent+
-|PROCESS_STARTED|流程实例已经启动。在启动之前创建的流程时分发。PROCESS_STARTED事件在相关的ENTITY_INITIALIZED事件,以及设置变量之后分发。|+org.flowable...FlowableEntityEvent+
-|PROCESS_COMPLETED|流程实例已经完成。在最后一个节点的 +$$ACTIVITY_COMPLETED $$+ 事件后分发。当流程实例没有任何路径可以继续时,流程结束。|+org.flowable...FlowableEntityEvent+
-|PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT| 流程已经到达终止结束事件(terminate end event)并结束。|+org.flowable...FlowableProcessTerminatedEvent+
-|PROCESS_CANCELLED|流程已经被取消。在流程实例从运行时中删除前分发。流程实例由API调用++RuntimeService.deleteProcessInstance++取消。|+org.flowable...FlowableCancelledEvent+
-|MEMBERSHIP_CREATED|用户已经加入组。本事件包含了相关的用户和组的id。|+org.flowable...FlowableMembershipEvent+
-|MEMBERSHIP_DELETED|用户已经从组中移出。本事件包含了相关的用户和组的id。|+org.flowable...FlowableMembershipEvent+
-|MEMBERSHIPS_DELETED|组的所有用户将被移出。本事件在用户移出前抛出,因此关联关系仍然可以访问。因为性能原因,不会再为每个被移出的用户抛出 +$$MEMBERSHIP_DELETED$$+ 事件。|+org.flowable...FlowableMembershipEvent+
-
-|===============
-
-
-引擎中所有的 +$$ENTITY_\*$$+ 事件都与实体关联。下表列出每个实体分发的实体事件:
-
-* *+$$ENTITY_CREATED, ENTITY_INITIALIZED, ENTITY_DELETED$$+*: 附件(Attachment),备注(Comment),部署(Deployment),执行(Execution),组(Group),身份关联(IdentityLink),作业(Job),模型(Model),流程定义(ProcessDefinition),流程实例(ProcessInstance),任务(Task),用户(User)。
-* *+$$ENTITY_UPDATED$$+*: 附件,部署,执行,组,身份关联,作业,模型,流程定义,流程实例,任务,用户。
-* *+$$ENTITY_SUSPENDED, ENTITY_ACTIVATED$$+*: 流程定义,流程实例/执行,任务。
-
-
-[[eventDispatcherRemarks]]
-
-
-==== 附加信息
-
-
-**监听器只会响应其所在引擎分发的事件。**因此如果在同一个数据库上运行不同的引擎,则只有该监听器注册的引擎生成的事件,才会分发给该监听器。其他引擎生成的事件不会分发给这个监听器,而不论这些引擎是否运行在同一个JVM下。
-
-某些事件类型(与实体相关)暴露了目标实体。按照事件类型的不同,有些实体不能被更新(如实体删除事件中的实体)。如果可能的话,请使用事件暴露的++EngineServices++来安全地操作引擎。即使这样,更新、操作事件中暴露的实体仍然需要小心。
-
-历史不会分发实体事件,因为它们都有对应的运行时实体分发事件。
-
diff --git a/docs/userguide/src/zh_CN/bpmn/ch04-API.adoc b/docs/userguide/src/zh_CN/bpmn/ch04-API.adoc
deleted file mode 100755
index 250773f4ddd..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch04-API.adoc
+++ /dev/null
@@ -1,450 +0,0 @@
-[[chapterApi]]
-
-== Flowable API
-
-[[apiEngine]]
-
-
-=== 流程引擎API与服务
-
-引擎API是与Flowable交互的最常用手段。总入口点是++ProcessEngine++。像<>章节中介绍的一样,ProcessEngine可以使用多种方式创建。使用ProcessEngine,可以获得各种提供工作流/BPM方法的服务。ProcessEngine与服务对象都是线程安全的,因此可以在服务器中保存并共用同一个引用。
-
-
-image::images/api.services.png[align="center"]
-
-[source,java,linenums]
-----
-ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
-
-RuntimeService runtimeService = processEngine.getRuntimeService();
-RepositoryService repositoryService = processEngine.getRepositoryService();
-TaskService taskService = processEngine.getTaskService();
-ManagementService managementService = processEngine.getManagementService();
-IdentityService identityService = processEngine.getIdentityService();
-HistoryService historyService = processEngine.getHistoryService();
-FormService formService = processEngine.getFormService();
-DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
-----
-
-在++ProcessEngines.getDefaultProcessEngine()++第一次被调用时,将初始化并构建流程引擎,之后的重复调用都会返回同一个流程引擎。可以通过++ProcessEngines.init()++创建流程引擎,并由++ProcessEngines.destroy()++关闭流程引擎。
-
-ProcessEngines会扫描++flowable.cfg.xml++与++flowable-context.xml++文件。对于++flowable.cfg.xml++文件,流程引擎会以标准Flowable方式构建引擎:++ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()++。对于++flowable-context.xml++文件,流程引擎会以Spring的方式构建:首先构建Spring应用上下文,然后从该上下文中获取流程引擎。
-
-所有的服务都是无状态的。这意味着你可以很容易的在集群环境的多个节点上运行Flowable,使用同一个数据库,而不用担心上一次调用实际在哪台机器上执行。不论在哪个节点执行,对任何服务的任何调用都是幂等(idempotent)的。
-
-**RepositoryService**很可能是使用Flowable引擎要用的第一个服务。这个服务提供了管理与控制++部署(deployments)++与++流程定义(process definitions)++的操作。在这里简单说明一下,流程定义是BPMN 2.0流程对应的Java对象,体现流程中每一步的结构与行为。++部署++是Flowable引擎中的包装单元,一个部署中可以包含多个BPMN 2.0 XML文件及其他资源。开发者可以决定在一个部署中包含的内容,可以是单个流程的BPMN 2.0 XML文件,也可以包含多个流程及其相关资源(如'hr-processes'部署可以包含所有与人力资源流程相关的的东西)。++RepositoryService++可用于++部署++这样的包。部署意味着将它上传至引擎,引擎将在储存至数据库之前检查与分析所有的流程。在部署操作后,可以在系统中使用这个部署包,部署包中的所有流程都可以启动。
-
-此外,这个服务还可以:
-
-* 查询引擎现有的部署与流程定义。
-* 暂停或激活部署中的某些流程,或整个部署。暂停意味着不能再对它进行操作,激活刚好相反,重新使它可以操作。
-* 获取各种资源,比如部署中保存的文件,或者引擎自动生成的流程图。
-* 获取POJO版本的流程定义。它可以用Java而不是XML的方式查看流程。
-
-与提供静态信息(也就是不会改变,至少不会经常改变的信息)的++RepositoryService++相反,**RuntimeService**用于启动流程定义的新流程实例。前面介绍过,++流程定义++中定义了流程中不同步骤的结构与行为。流程实例则是流程定义的实际执行过程。同一时刻,一个流程定义通常有多个运行中的实例。++RuntimeService++也用于读取与存储++流程变量++。流程变量是流程实例中的数据,可以在流程的许多地方使用(例如排他网关经常使用流程变量判断流程下一步要走的路径)。++RuntimeService++还可以用于查询流程实例与执行(Execution)。执行也就是BPMN 2.0中 +$$'token'$$+ 的概念。通常执行是指向流程实例当前位置的指针。最后,还可以在流程实例等待外部触发时使用++RuntimeService++,使流程可以继续运行。流程有许多++等待状态(wait states)++,++RuntimeService++服务提供了许多操作用于“通知”流程实例:已经接收到外部触发,流程实例可以继续运行。
-
-
-对于像Flowable这样的BPM引擎来说,核心是需要人类用户操作的任务。所有任务相关的东西都组织在**TaskService**中,例如:
-
-* 查询分派给用户或组的任务
-* 创建__独立运行(standalone)__任务。这是一种没有关联到流程实例的任务。
-* 决定任务的执行用户(assignee),或者将用户通过某种方式与任务关联。
-* 认领(claim)与完成(complete)任务。认领是指某人决定成为任务的执行用户,也即他将会完成这个任务。完成任务是指“做这个任务要求的工作”,通常是填写某个表单。
-
-**IdentityService**很简单。它用于管理(创建,更新,删除,查询……)组与用户。请注意,Flowable实际上在运行时并不做任何用户检查。例如任务可以分派给任何用户,而引擎并不会验证系统中是否存在该用户。这是因为Flowable有时要与LDAP、Active Directory等服务结合使用。
-
-**FormService**是可选服务。也就是说Flowable没有它也能很好地运行,而不必牺牲任何功能。这个服务引入了__开始表单(start form)__与__任务表单(task form)__的概念。 __开始表单__是在流程实例启动前显示的表单,而__任务表单__是用户完成任务时显示的表单。Flowable可以在BPMN 2.0流程定义中定义这些表单。表单服务通过简单的方式暴露这些数据。再次重申,表单不一定要嵌入流程定义,因此这个服务是可选的。
-
-**HistoryService**暴露Flowable引擎收集的所有历史数据。当执行流程时,引擎会保存许多数据(可配置),例如流程实例启动时间、谁在执行哪个任务、完成任务花费的事件、每个流程实例的执行路径,等等。这个服务主要提供查询这些数据的能力。
-
-**ManagementService**通常在用Flowable编写用户应用时不需要使用。它可以读取数据库表与表原始数据的信息,也提供了对作业(job)的查询与管理操作。Flowable中很多地方都使用作业,例如定时器(timer),异步操作(asynchronous continuation),延时暂停/激活(delayed suspension/activation)等等。后续会详细介绍这些内容。
-
-
-**DynamicBpmnService**可用于修改流程定义中的部分内容,而不需要重新部署它。例如可以修改流程定义中一个用户任务的办理人设置,或者修改一个服务任务中的类名。
-
-参考link:$$http://www.flowable.org/docs/javadocs/index.html$$[javadocs]了解服务操作与引擎API的更多信息。
-
-[[_exception_strategy]]
-=== 异常策略
-
-Flowable的异常基类是++org.flowable.engine.FlowableException++,这是一个非受检异常(unchecked exception)。在任何API操作时都可能会抛出这个异常,link:$$http://www.flowable.org/docs/javadocs/index.html$$[javadoc]提供了每个方法可能抛出的异常。例如,从++TaskService++中摘录:
-
-[source,java,linenums]
-----
-/**
- * 当任务成功执行时调用。
- * @param taskId 需要完成的任务id,不能为null。
- * @throws FlowableObjectNotFoundException 若给定id找不到任务。
- */
- void complete(String taskId);
-----
-
-在上例中,如果所用的id找不到任务,就会抛出异常。并且,由于javadoc中**明确要求taskId不能为null,因此如果传递了++null++值,会抛出++FlowableIllegalArgumentException++异常**。
-
-尽管我们想避免过大的异常层次结构,但在特定情况下仍然会抛出下述异常子类。所有流程执行与API调用中发生的错误,如果不符合下面列出的异常,会统一抛出++FlowableExceptions++。
-
-* ++FlowableWrongDbException++: 当Flowable引擎检测到数据库表结构版本与引擎版本不匹配时抛出。
-* ++FlowableOptimisticLockingException++: 当对同一数据实体的并发访问导致数据存储发生乐观锁异常时抛出。
-* ++FlowableClassLoadingException++: 当需要载入的类(如JavaDelegate, TaskListener, ...)无法找到,或载入发生错误时抛出。
-* ++FlowableObjectNotFoundException++: 当请求或要操作的对象不存在时抛出。
-* ++FlowableIllegalArgumentException++: 当调用Flowable API时使用了不合法的参数时抛出。可能是引擎配置中的不合法值,或者是API调用传递的不合法参数,也可能是流程定义中的不合法值。
-* ++FlowableTaskAlreadyClaimedException++: 当对已被认领的任务调用++taskService.claim(...)++时抛出。
-
-
-[[queryAPI]]
-
-
-=== 查询API
-
-从引擎中查询数据有两种方式:查询API与原生(native)查询。查询API可以使用链式API,通过编程方式进行类型安全的查询。你可以在查询中增加各种条件(所有条件都用做AND逻辑),也可以明确指定排序方式。下面是示例代码:
-
-[source,java,linenums]
-----
-List tasks = taskService.createTaskQuery()
- .taskAssignee("kermit")
- .processVariableValueEquals("orderId", "0815")
- .orderByDueDate().asc()
- .list();
-----
-
-有时需要更复杂的查询,例如使用OR操作符查询,或者使用查询API不能满足查询条件要求。我们为这种需求提供了可以自己写SQL查询的原生查询。返回类型由使用的查询对象决定,数据会映射到正确的对象中(Task、ProcessInstance、Execution,等等)。查询在数据库中进行,因此需要使用数据库中定义的表名与列名。这需要了解内部数据结构,因此建议小心使用原生查询。数据库表名可以通过API读取,这样可以将依赖关系减到最小。
-
-[source,java,linenums]
-----
-List tasks = taskService.createNativeTaskQuery()
- .sql("SELECT * FROM " + managementService.getTableName(Task.class) +
- " T WHERE T.NAME_ = #{taskName}")
- .parameter("taskName", "gonzoTask")
- .list();
-
-long count = taskService.createNativeTaskQuery()
- .sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T1, " +
- managementService.getTableName(VariableInstanceEntity.class) + " V1 WHERE V1.TASK_ID_ = T1.ID_")
- .count();
-----
-
-[[apiVariables]]
-
-=== 变量
-
-流程实例按步骤执行时,需要使用一些数据。在Flowable中,这些数据称作__变量(variable)__,并会存储在数据库中。变量可以用在表达式中(例如在排他网关中用于选择正确的出口路径),也可以在Java服务任务(service task)中用于调用外部服务(例如为服务调用提供输入或结果存储),等等。
-
-流程实例可以持有变量(称作__流程变量 process variables__);用户任务以及__执行(executions)__——流程当前活动节点的指针——也可以持有变量。流程实例可以持有任意数量的变量,每个变量存储为__ACT_RU_VARIABLE__数据库表的一行。
-
-
-所有的__startProcessInstanceXXX__方法都有一个可选参数,用于在流程实例创建及启动时设置变量。例如,在__RuntimeService__中:
-
-[source,java,linenums]
-----
-ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map variables);
-----
-
-也可以在流程执行中加入变量。例如,(_RuntimeService_):
-
-[source,java,linenums]
-----
-void setVariable(String executionId, String variableName, Object value);
-void setVariableLocal(String executionId, String variableName, Object value);
-void setVariables(String executionId, Map variables);
-void setVariablesLocal(String executionId, Map variables);
-----
-
-请注意可以为给定执行(请记住,流程实例由一颗执行的树(tree of executions)组成)设置__局部(local)__变量。局部变量将只在该执行中可见,对执行树的上层则不可见。这可以用于 数据不应该暴露给流程实例的其他执行,或者变量在流程实例的不同路径中有不同的值(例如使用并行路径时)的情况。
-
-可以用下列方法读取变量。请注意__TaskService__中有类似的方法。这意味着任务与执行一样,可以持有局部变量,其生存期为任务持续的时间。
-
-
-[source,java,linenums]
-----
-Map getVariables(String executionId);
-Map getVariablesLocal(String executionId);
-Map getVariables(String executionId, Collection variableNames);
-Map getVariablesLocal(String executionId, Collection variableNames);
-Object getVariable(String executionId, String variableName);
- T getVariable(String executionId, String variableName, Class variableClass);
-----
-
-变量通常用于<>、<>、执行(execution)、任务监听器(tasklisteners)、脚本(scripts)等等。在这些结构中,提供了当前的__execution__或__task__对象,可用于变量的设置、读取。简单示例如下:
-
-[source,java,linenums]
-----
-execution.getVariables();
-execution.getVariables(Collection variableNames);
-execution.getVariable(String variableName);
-
-execution.setVariables(Map variables);
-execution.setVariable(String variableName, Object value);
-----
-
-请注意也可以使用上例中方法的__局部变量__版本。
-
-由于历史(与向后兼容)原因,当调用上述任何方法时,引擎会从数据库中取出**所有**变量。也就是说,如果你有10个变量,使用__getVariable("myVariable")__获取其中的一个,实际上其他9个变量也会从数据库取出并缓存。这并不坏,因为后续的调用可以不必再读取数据库。比如,如果流程定义包含三个连续的服务任务(因此它们在同一个数据库事务里),在第一个服务任务里通过一次调用获取全部变量,也许比在每个服务任务里分别获取需要的变量要好。请注意对读取与设置变量**都是这样**。
-
-当然,如果使用大量变量,或者你希望精细控制数据库查询与流量,上述的做法就不合适了。我们引入了可以更精细控制的方法。这个方法有一个可选的参数,告诉引擎是否需要读取并缓存所有变量:
-
-[source,java,linenums]
-----
-Map getVariables(Collection variableNames, boolean fetchAllVariables);
-Object getVariable(String variableName, boolean fetchAllVariables);
-void setVariable(String variableName, Object value, boolean fetchAllVariables);
-----
-
-当__fetchAllVariables__参数为__true__时,行为与上面描述的完全一样:读取或设置一个变量时,所有的变量都将被读取并缓存。
-
-而当参数值为__false__时,会使用明确的查询,其他变量不会被读取或缓存。只有指定的变量的值会被缓存并用于后续使用。
-
-
-[[apiTransientVariables]]
-
-=== 瞬时变量
-
-瞬时变量(Transient variable)类似普通变量,只是不会被持久化。通常来说,瞬时变量用于高级使用场景。如果不明确,还是使用普通流程变量为好。
-
-瞬时变量具有下列特性:
-
-* 瞬时变量完全不存储历史。
-* 与__普通__变量类似,设置瞬时变量时会存入__最上层父__中。这意味着在一个执行中设置一个变量时,瞬时变量实际上会存储在流程实例执行中。与普通变量类似,可以使用__局部(local)__的对应方法,将变量设置为某个执行或任务的局部变量。
-* 瞬时变量只能在下一个“等待状态”之前访问。之后该变量即消失。等待状态意味着流程实例会持久化至数据存储中。请注意在这个定义中,__异步__活动也是“等待状态”!
-* 只能使用__setTransientVariable(name, value)__设置瞬时变量,但是调用__getVariable(name)__也会返回瞬时变量(也有__getTransientVariable(name)__方法,它只会返回瞬时变量)。这是为了简化表达式的撰写,并保证已有逻辑可以使用这两种类型的变量。
-* 瞬时变量__屏蔽(shadow)__同名的持久化变量。也就是说当一个流程实例中设置了同名的持久化变量与瞬时变量时,__getVariable("someVariable")__会返回瞬时变量的值。
-
-在大多数可以使用普通变量的地方,都可以获取、设置瞬时变量:
-
-* 在__JavaDelegate__实现中的__DelegateExecution__内
-* 在__ExecutionListener__实现中的__DelegateExecution__内,以及在__TaskListener__实现中的__DelegateTask__内
-* 通过__execution__对象在脚本任务内
-* 通过RuntimeService启动流程实例时
-* 完成任务时
-* 调用__runtimeService.trigger__方法时
-
-
-瞬时变量相关的方法遵循普通流程变量方法的命名约定:
-
-[source,java,linenums]
-----
-void setTransientVariable(String variableName, Object variableValue);
-void setTransientVariableLocal(String variableName, Object variableValue);
-void setTransientVariables(Map transientVariables);
-void setTransientVariablesLocal(Map transientVariables);
-
-Object getTransientVariable(String variableName);
-Object getTransientVariableLocal(String variableName);
-
-Map getTransientVariables();
-Map getTransientVariablesLocal();
-
-void removeTransientVariable(String variableName);
-void removeTransientVariableLocal(String variableName);
-----
-
-下面的BPMN流程图展示了一个典型例子:
-
-image::images/api.transient.variable.example.png[align="center"]
-
-假设'Fetch Data(获取数据)'服务任务调用某个远程服务(例如使用REST)。也假设需要其需要一些配置参数,并需要在启动流程实例时提供。同时,这些配置参数对于历史审计并不重要,因此我们将它们作为瞬时变量传递:
-
-[source,java,linenums]
-----
-ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
- .processDefinitionKey("someKey")
- .transientVariable("configParam01", "A")
- .transientVariable("configParam02", "B")
- .transientVariable("configParam03", "C")
- .start();
-----
-
-请注意在到达用户任务并持久化之前,都可以使用这些瞬时变量。例如,在'Additional Work(额外工作)'用户任务中它们就不再可用。也请注意如果'Fetch Data'是异步的,则瞬时变量在该步骤之后也不再可用。
-
-
-'Fetch Data'(的简化版本)可以像是:
-
-[source,java,linenums]
-----
-public static class FetchDataServiceTask implements JavaDelegate {
- public void execute(DelegateExecution execution) {
- String configParam01 = (String) execution.getVariable(configParam01);
- // ...
-
- RestResponse restResponse = executeRestCall();
- execution.setTransientVariable("response", restResponse.getBody());
- execution.setTransientVariable("status", restResponse.getStatus());
- }
-}
-----
-
-'Process Data(处理数据)'可以获取response瞬时变量,解析并将其相关数据存储在实际流程变量中,因为之后还需要使用它们。
-
-离开排他网关的顺序流上的条件表达式,不关注使用的是持久化还是瞬时变量(在这个例子中__status__是瞬时变量):
-
-[source,xml,linenums]
-----
-${status == 200}
-----
-
-[[apiExpressions]]
-
-
-=== 表达式
-
-Flowable使用UEL进行表达式解析。UEL代表__Unified Expression Language__,是EE6规范的一部分(查看link:$$http://docs.oracle.com/javaee/6/tutorial/doc/gjddd.html$$[EE6规范]了解更多信息)。
-
-表达式可以用于<>、<>、<> 与 <>等。尽管有值表达式与方法表达式这两种不同的表达式,Flowable通过抽象,使它们都可以在需要++表达式++的地方使用。
-
-* **值表达式 Value expression**: 解析为一个值。默认情况下,所有流程变量都可以使用。(若使用Spring)所有的Spring bean也可以用在表达式里。例如:
-
-----
-${myVar}
-${myBean.myProperty}
-----
-
-* **方法表达式 Method expression**: 调用一个方法,可以带或不带参数。**当调用不带参数的方法时,要确保在方法名后添加空括号(以避免与值表达式混淆)。**传递的参数可以是字面值(literal value),也可以是表达式,它们会被自动解析。例如:
-
-----
-${printer.print()}
-${myBean.addNewOrder('orderName')}
-${myBean.doSomething(myVar, execution)}
-----
-
-请注意,表达式支持解析(及比较)原始类型(primitive)、bean、list、array与map。
-Note that these expressions support resolving primitives (including comparing them), beans, lists, arrays and maps.
-
-除了所有流程变量外,还有一些默认对象可在表达式中使用:
-
-* ++execution++: +DelegateExecution++,持有正在运行的执行的额外信息。
-* ++task++: ++DelegateTask++持有当前任务的额外信息。**请注意:只在任务监听器的表达式中可用。**
-* ++authenticatedUserId++: 当前已验证的用户id。如果没有已验证的用户,该变量不可用。
-
-更多实际使用例子,请查看<>、<>、<>、<>或者<>等章节。
-
-
-[[apiUnitTesting]]
-
-=== 单元测试
-
-业务流程是软件项目的必要组成部分,也需要使用测试一般应用逻辑的方法——单元测试——测试它们。Flowable是嵌入式的Java引擎,因此为业务流程编写单元测试就同编写一般的单元测试一样简单。
-
-Flowable支持JUnit 3及4的单元测试风格。按照JUnit 3的风格,必须扩展(extended)++org.flowable.engine.test.FlowableTestCase++。它通过保护(protected)成员变量提供对ProcessEngine与服务的访问。在测试的++setup()++中,processEngine会默认使用classpath中的++flowable.cfg.xml++资源初始化。如果要指定不同的配置文件,请覆盖__getConfigurationResource()__方法。当使用相同的配置资源时,流程引擎会静态缓存,用于多个单元测试。
-
-通过扩展++FlowableTestCase++,可以使用++org.flowable.engine.test.Deployment++注解测试方法。在测试运行前,会部署与测试类在同一个包下的格式为++testClassName.testMethod.bpmn20.xml++的资源文件。在测试结束时,会删除这个部署,包括所有相关的流程实例、任务,等等。也可以使用++Deployment++注解显式指定资源位置。查看该类以获得更多信息。
-
-综上所述,JUnit 3风格的测试看起来类似:
-
-[source,java,linenums]
-----
-public class MyBusinessProcessTest extends FlowableTestCase {
-
- @Deployment
- public void testSimpleProcess() {
- runtimeService.startProcessInstanceByKey("simpleProcess");
-
- Task task = taskService.createTaskQuery().singleResult();
- assertEquals("My Task", task.getName());
-
- taskService.complete(task.getId());
- assertEquals(0, runtimeService.createProcessInstanceQuery().count());
- }
-}
-----
-
-要使用JUnit 4的风格书写单元测试并达成同样的功能,必须使用++org.flowable.engine.test.FlowableRule++ Rule。这样能够通过它的getter获得流程引擎与服务。对于++FlowableTestCase++(上例),包含++@Rule++就可以使用++org.flowable.engine.test.Deployment++注解(参见上例解释其用途及配置),并且会自动在classpath中寻找默认配置文件。当使用相同的配置资源时,流程引擎会静态缓存,以用于多个单元测试。
-
-下面的代码片段展示了JUnit 4风格的测试与++FlowableRule++的用法。
-
-[source,java,linenums]
-----
-public class MyBusinessProcessTest {
-
- @Rule
- public FlowableRule flowableRule = new FlowableRule();
-
- @Test
- @Deployment
- public void ruleUsageExample() {
- RuntimeService runtimeService = flowableRule.getRuntimeService();
- runtimeService.startProcessInstanceByKey("ruleUsage");
-
- TaskService taskService = flowableRule.getTaskService();
- Task task = taskService.createTaskQuery().singleResult();
- assertEquals("My Task", task.getName());
-
- taskService.complete(task.getId());
- assertEquals(0, runtimeService.createProcessInstanceQuery().count());
- }
-}
-----
-
-[[apiDebuggingUnitTest]]
-
-
-=== 调试单元测试
-
-当使用H2内存数据库进行单元测试时,下面的方法可以让你在调试过程中方便地检查Flowable数据库中的数据。截图来自Eclipse,但其他IDE方式相似。
-
-假设我们的单元测试的某处放置了__断点(breakpoint)__(在Eclipse里可以通过在代码左侧条上双击实现):
-
-image::images/api.test.debug.breakpoint.png[align="center"]
-
-如果我们在__debug__模式(在测试类中右键,选择“Run as”,然后选择“JUnit test”)下运行单元测试,测试进程会在断点处暂停,这样我们就可以在右上窗口中查看测试中的变量。
-
-image::images/api.test.debug.view.png[align="center"]
-
-要检查Flowable的数据,打开__Display__窗口(如果没有找到这个窗口,打开 Window->Show View->Other,然后选择__Display__),并键入(可以使用代码补全)++org.h2.tools.Server.createWebServer("-web").start()++
-
-image::images/api.test.debug.start.h2.server.png[align="center"]
-
-选中刚键入的行并右键点击。然后选择'Display'(或者用快捷键执行)
-
-image::images/api.test.debug.start.h2.server.2.png[align="center"]
-
-现在打开浏览器并访问link:$$http://localhost:8082$$[http://localhost:8082],填入内存数据库的JDBC URL(默认为++jdbc:h2:mem:flowable++),然后点击connect按钮。
-
-image::images/api.test.debug.h2.login.png[align="center"]
-
-这样就可以看到Flowable的数据。便于理解单元测试执行流程的方式。
-
-image::images/api.test.debug.h2.tables.png[align="center"]
-
-
-
-[[apiProcessEngineInWebApp]]
-
-
-=== Web应用中的流程引擎
-
-++ProcessEngine++是线程安全的类,可以很容易地在多个线程间共享。在web应用中,这意味着可以在容器启动时创建引擎,并在容器关闭时关闭引擎。
-
-下面的代码片段展示了如何在Servlet环境中,通过++ServletContextListener++初始化与销毁流程引擎。
-
-
-[source,java,linenums]
-----
-public class ProcessEnginesServletContextListener implements ServletContextListener {
-
- public void contextInitialized(ServletContextEvent servletContextEvent) {
- ProcessEngines.init();
- }
-
- public void contextDestroyed(ServletContextEvent servletContextEvent) {
- ProcessEngines.destroy();
- }
-
-}
-----
-
-++contextInitialized++方法会调用++ProcessEngines.init()++。它会在classpath中查找++flowable.cfg.xml++资源文件,并为每个文件分别创建++ProcessEngine++(如果多个JAR都包含配置文件)。如果在classpath中有多个这样的资源文件,请确保它们使用不同的引擎名。需要使用流程引擎时,可以这样获取:
-
-[source,java,linenums]
-----
-ProcessEngines.getDefaultProcessEngine()
-----
-
-或者
-
-[source,java,linenums]
-----
-ProcessEngines.getProcessEngine("myName");
-----
-
-当然,就像<>章节中介绍的,还可以使用各种不同的方式创建流程引擎。
-
-context-listener的++contextDestroyed++方法会调用++ProcessEngines.destroy()++。它会妥善关闭所有已初始化的流程引擎。
diff --git a/docs/userguide/src/zh_CN/bpmn/ch05-Spring.adoc b/docs/userguide/src/zh_CN/bpmn/ch05-Spring.adoc
deleted file mode 100755
index d1a0e429082..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch05-Spring.adoc
+++ /dev/null
@@ -1,328 +0,0 @@
-[[springintegration]]
-
-== 集成Spring
-
-尽管完全可以脱离Spring使用Flowable,我们仍提供了很多非常好的集成特性,并将在这一章节介绍。
-
-=== ProcessEngineFactoryBean
-
-可以将++ProcessEngine++配置为普通的Spring bean。入口是++org.flowable.spring.ProcessEngineFactoryBean++类。这个bean处理流程引擎配置,并创建流程引擎。所以在Spring中创建与设置的参数与<>章节中介绍的相同。Spring集成所用的配置与引擎bean为:
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-
-
-
-----
-
-请注意++processEngineConfiguration++ bean现在使用++org.flowable.spring.SpringProcessEngineConfiguration++类。
-
-[[_transactions]]
-=== 事务
-
-我们会逐步说明(Flowable)发行版里,Spring示例中的++SpringTransactionIntegrationTest++。下面是我们示例中使用的Spring配置文件(SpringTransactionIntegrationTest-context.xml)。下面的小节包含了dataSource(数据源),transactionManager(事务管理器),processEngine(流程引擎)以及Flowable引擎服务。
-
-将DataSource传递给++SpringProcessEngineConfiguration++(使用“dataSource”参数)时,Flowable会在内部使用++org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy++对得到的数据源进行包装(wrap)。这是为了保证从数据源获取的SQL连接与Spring的事务可以协同工作。这样也就不需要在Spring配置中对数据源进行代理(proxy)。但仍然可以将代理++TransactionAwareDataSourceProxy++传递给++SpringProcessEngineConfiguration++——在这种情况下,不会再进行包装。
-
-**请确保如果自行在Spring配置中声明了++TransactionAwareDataSourceProxy++,则不要将它用在已经配置Spring事务的资源上(例如DataSourceTransactionManager与JPATransactionManager。它们需要未经代理的数据源)。**
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-...
-----
-
-这个Spring配置文件也包含了在这个示例中要用到的bean与配置:
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-
-
-
-
-
-
-----
-
-可以使用任何Spring支持的方式创建应用上下文(application context)。在这个例子中,可以使用classpath中的XML资源配置来创建Spring应用上下文:
-
-
-[source,java,linenums]
-----
-ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
- "org/flowable/examples/spring/SpringTransactionIntegrationTest-context.xml");
-----
-
-或者在单元测试中:
-
-[source,java,linenums]
-----
-@ContextConfiguration(
- "classpath:org/flowable/spring/test/transaction/SpringTransactionIntegrationTest-context.xml")
-----
-
-然后就可以获取服务bean,并调用它们的方法。ProcessEngineFactoryBean会为服务加上额外的拦截器(interceptor),并为Flowable服务方法设置Propagation.REQUIRED事务级别。这样,我们就可以使用repositoryService部署流程:
-
-[source,java,linenums]
-----
-RepositoryService repositoryService =
- (RepositoryService) applicationContext.getBean("repositoryService");
-String deploymentId = repositoryService
- .createDeployment()
- .addClasspathResource("org/flowable/spring/test/hello.bpmn20.xml")
- .deploy()
- .getId();
-
-----
-
-还有另一种方法也可以使用。如果userBean.hello()方法在Spring事务中,Flowable服务方法调用就会加入这个事务。
-
-[source,java,linenums]
-----
-UserBean userBean = (UserBean) applicationContext.getBean("userBean");
-userBean.hello();
-----
-
-UserBean看起来像下面这样。请记着在上面的Spring bean配置中,我们已经将repositoryService注入了userBean。
-
-[source,java,linenums]
-----
-public class UserBean {
-
- /** 已经由Spring注入 */
- private RuntimeService runtimeService;
-
- @Transactional
- public void hello() {
- // 可以在你的领域模型(domain model)中进行事务操作,
- // 它会与Flowable RuntimeService的startProcessInstanceByKey
- // 合并在同一个事务里
- runtimeService.startProcessInstanceByKey("helloProcess");
- }
-
- public void setRuntimeService(RuntimeService runtimeService) {
- this.runtimeService = runtimeService;
- }
-}
-----
-
-[[springExpressions]]
-
-
-=== 表达式
-
-当使用ProcessEngineFactoryBean时,默认BPMN流程中所有的<>都可以“看见”所有的Spring bean。可以通过配置的map,限制表达式能使用的bean,甚至可以完全禁止表达式使用bean。下面的例子只暴露了一个bean(printer),可以使用“printer”作为key访问。**要完全禁止表达式使用bean,可以将SpringProcessEngineConfiguration的‘beans’参数设为空list。如果不设置‘beans’参数,则上下文中的所有bean都将可以使用。**
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-
-
-
-----
-
-这样就可以在表达式中使用这个bean了。例如,SpringTransactionIntegrationTest ++hello.bpmn20.xml++展示了如何通过UEL方法表达式(method expression)调用Spring bean:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-其中++Printer++为:
-
-[source,java,linenums]
-----
-public class Printer {
-
- public void printMessage() {
- System.out.println("hello world");
- }
-}
-----
-
-Spring bean配置(上面已经展示过)为:
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-
-----
-
-[[_automatic_resource_deployment]]
-=== 自动部署资源
-
-集成Spring也提供了部署资源的特殊方式。在流程引擎配置中,可以指定一组资源。当创建流程引擎时,会扫描并部署这些资源。可以用过滤器阻止重复部署:只有当资源确实发生变化时,才会重新部署至Flowable数据库。在Spring容器经常重启(例如测试时)的时候,这很有用。
-
-这里有个例子:
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-
-
-
-----
-
-默认情况下,上面的配置方式会将符合这个过滤器的所有资源组织在一起,作为Flowable引擎的一个部署。重复检测过滤器将作用于整个部署,避免重复地部署未改变资源。有时这不是你想要的。例如,如果用这种方式部署了一组资源,即使只有其中的一个资源发生了改变,整个部署都会被视作已改变,因此这个部署中所有的所有流程定义都会被重新部署。这将导致每个流程定义都会刷新版本号(流程定义id会变化),即使实际上只有一个流程发生了变化。
-
-可以使用++SpringProcessEngineConfiguration++中的额外参数+deploymentMode+,定制部署的方式。这个参数定义了对于一组符合过滤器的资源,组织部署的方式。默认这个参数有3个可用值:
-
-* ++default++: 将所有资源组织在一个部署中,整体用于重复检测过滤。这是默认值,在未设置这个参数时也会用这个值。
-* ++single-resource++: 为每个资源创建一个单独的部署,并用于重复检测过滤。如果希望单独部署每一个流程定义,并且只有在它发生变化时才创建新的流程定义版本,就应该使用这个值。
-* ++resource-parent-folder++: 为同一个目录下的资源创建一个单独的部署,并用于重复检测过滤。这个参数值可以为大多数资源创建独立的部署。同时仍可以通过将部分资源放在同一个目录下,将它们组织在一起。这里有一个将++deploymentMode++设置为++single-resource++的例子:
-
-
-[source,xml,linenums]
-----
-
- ...
-
-
-
-----
-
-如果上述++deploymentMode++的参数值不能满足要求,还可以自定义组织部署的行为。创建++SpringProcessEngineConfiguration++的子类,并覆盖++getAutoDeploymentStrategy(String deploymentMode)++方法。这个方法用于确定对给定的++deploymentMode++参数值,应使用何种部署策略。
-
-
-[[springUnitTest]]
-
-
-=== 单元测试
-
-与Spring集成后,业务流程可以非常简单地使用标准的 <>进行测试。下面的例子展示了如何通过典型的基于Spring的单元测试,对业务流程进行测试:
-
-[source,java,linenums]
-----
-@RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration("classpath:org/flowable/spring/test/junit4/springTypicalUsageTest-context.xml")
-public class MyBusinessProcessTest {
-
- @Autowired
- private RuntimeService runtimeService;
-
- @Autowired
- private TaskService taskService;
-
- @Autowired
- @Rule
- public FlowableRule flowableSpringRule;
-
- @Test
- @Deployment
- public void simpleProcessTest() {
- runtimeService.startProcessInstanceByKey("simpleProcess");
- Task task = taskService.createTaskQuery().singleResult();
- assertEquals("My Task", task.getName());
-
- taskService.complete(task.getId());
- assertEquals(0, runtimeService.createProcessInstanceQuery().count());
-
- }
-}
-----
-
-请注意要让这个例子可以正常工作,需要在Spring配置中定义__org.flowable.engine.test.FlowableRule__ bean(在上面的例子中通过@Autowire注入)。
-
-
-[source,xml,linenums]
-----
-
-
-
-
-----
-
-
-[[_jpa_with_hibernate_4_2_x]]
-=== 通过Hibernate 4.2.x使用JPA
-
-要在Flowable引擎的服务任务或者监听器逻辑中使用Hibernate 4.2.x JPA,需要添加Spring ORM的额外依赖。对Hibernate 4.1.x或更低则不需要。需要添加的依赖为:
-
-[source,xml,linenums]
-----
-
- org.springframework
- spring-orm
- ${org.springframework.version}
-
-----
-
-
diff --git a/docs/userguide/src/zh_CN/bpmn/ch05a-Spring-Boot.adoc b/docs/userguide/src/zh_CN/bpmn/ch05a-Spring-Boot.adoc
deleted file mode 100755
index ce9e0129614..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch05a-Spring-Boot.adoc
+++ /dev/null
@@ -1,1045 +0,0 @@
-
-[[springSpringBoot]]
-
-
-=== Spring Boot
-
-Spring Boot是一个应用框架。按照link:$$http://projects.spring.io/spring-boot/$$[其官网]的介绍,可以__轻松地创建独立运行的,生产级别的,基于Spring的应用,并且可以“直接运行”。它基于约定大于配置的原则使用Spring框架与第三方库,使你可以轻松地开始使用。大多数Spring Boot应用只需要很少的Spring配置__。
-
-要获得更多关于Spring Boot的信息,请查阅link:$$http://projects.spring.io/spring-boot/$$[http://projects.spring.io/spring-boot/]
-
-Flowable与Spring Boot的集成是我们与Spring的提交者共同开发的。
-
-[[_compatibility]]
-==== 兼容性
-
-Flowable使用同一个starter支持Spring Boot 2.0及1.5。主要支持Spring Boot 2.0。所以监控(actuator) endpoint只支持2.0。Flowable的starter直接引用Spring Boot starter,所以如果需要使用1.5版的Spring Boot starter,需要自行定义。
-
-[[_getting_started_2]]
-==== 开始
-
-Spring Boot提倡约定大于配置。要开始工作,只需在项目中添加__flowable-spring-boot-starter__或__flowable-spring-boot-starter-rest__依赖。如果不需要引入所有的引擎,可以查看其它的<>。
-如使用Maven:
-
-
-[source,xml,linenums]
-----
-
- org.flowable
- flowable-spring-boot-starter
- ${flowable.version}
-
-----
-
-就这么简单。这个依赖会自动向classpath添加正确的Flowable与Spring依赖。现在可以编写Spring Boot应用了:
-
-[source,java,,linenums]
-----
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication(proxyBeanMethods = false)
-public class MyApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(MyApplication.class, args);
- }
-
-}
-----
-
-Flowable需要数据库来存储数据。运行上面的代码会得到异常提示,指出需要在classpath中添加数据库驱动依赖。现在添加H2数据库依赖:
-
-[source,xml,linenums]
-----
-
- com.h2database
- h2
- 1.4.197
-
-----
-
-应用这次可以启动了。你会看到类似这样的输出:
-
-----
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
-( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v2.0.0.RELEASE)
-
-MyApplication : Starting MyApplication on ...
-MyApplication : No active profile set, falling back to default profiles: default
-ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@4fdfa676: startup date [Wed Mar 28 12:04:00 CEST 2018]; root of context hierarchy
-o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
-o.apache.catalina.core.StandardService : Starting service [Tomcat]
-org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.28
-o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
-o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3085 ms
-o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]
-o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable IDM Rest API mapped to [/idm-api/*]
-o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable Form Rest API mapped to [/form-api/*]
-o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable DMN Rest API mapped to [/dmn-api/*]
-o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable Content Rest API mapped to [/content-api/*]
-o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable CMMN Rest API mapped to [/cmmn-api/*]
-o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable BPMN Rest API mapped to [/process-api/*]
-o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
-o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
-o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
-o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
-uration$$EnhancerBySpringCGLIB$$3d0c70ac : No deployment resources were found for autodeployment
-uration$$EnhancerBySpringCGLIB$$8131eb1a : No deployment resources were found for autodeployment
-o.f.e.i.c.ProcessEngineConfigurationImpl : Found 5 Engine Configurators in total:
-o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.spring.configurator.SpringIdmEngineConfigurator (priority:100000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.dmn.spring.configurator.SpringDmnEngineConfigurator (priority:200000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.form.spring.configurator.SpringFormEngineConfigurator (priority:300000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.content.spring.configurator.SpringContentEngineConfigurator (priority:400000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.cmmn.spring.configurator.SpringCmmnEngineConfigurator (priority:500000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.spring.configurator.SpringIdmEngineConfigurator (priority:100000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.dmn.spring.configurator.SpringDmnEngineConfigurator (priority:200000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.form.spring.configurator.SpringFormEngineConfigurator (priority:300000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.content.spring.configurator.SpringContentEngineConfigurator (priority:400000)
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.cmmn.spring.configurator.SpringCmmnEngineConfigurator (priority:500000)
-com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
-com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.spring.configurator.SpringIdmEngineConfigurator (priority:100000)
-.d.AbstractSqlScriptBasedDbSchemaManager : performing create on identity with resource org/flowable/idm/db/create/flowable.h2.create.identity.sql
-o.f.idm.engine.impl.IdmEngineImpl : IdmEngine default created
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.dmn.spring.configurator.SpringDmnEngineConfigurator (priority:200000)
-o.f.dmn.engine.impl.DmnEngineImpl : DmnEngine default created
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.form.spring.configurator.SpringFormEngineConfigurator (priority:300000)
-o.f.form.engine.impl.FormEngineImpl : FormEngine default created
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.content.spring.configurator.SpringContentEngineConfigurator (priority:400000)
-o.f.c.engine.ContentEngineConfiguration : Content file system root : ...
-o.f.c.engine.impl.ContentEngineImpl : ContentEngine default created
-o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.cmmn.spring.configurator.SpringCmmnEngineConfigurator (priority:500000)
-o.f.cmmn.engine.CmmnEngineConfiguration : Found 1 Engine Configurators in total:
-o.f.cmmn.engine.CmmnEngineConfiguration : class org.flowable.cmmn.engine.impl.cfg.IdmEngineConfigurator (priority:100000)
-o.f.cmmn.engine.CmmnEngineConfiguration : Executing beforeInit() of class org.flowable.cmmn.engine.impl.cfg.IdmEngineConfigurator (priority:100000)
-o.f.cmmn.engine.CmmnEngineConfiguration : Executing configure() of class org.flowable.cmmn.engine.impl.cfg.IdmEngineConfigurator (priority:100000)
-o.f.idm.engine.impl.IdmEngineImpl : IdmEngine default created
-o.f.cmmn.engine.impl.CmmnEngineImpl : CmmnEngine default created
-o.f.engine.impl.ProcessEngineImpl : ProcessEngine default created
-o.f.j.s.i.a.AbstractAsyncExecutor : Starting up the async job executor [org.flowable.spring.job.service.SpringAsyncExecutor].
-o.f.j.s.i.a.AcquireAsyncJobsDueRunnable : starting to acquire async jobs due
-o.f.j.s.i.a.AcquireTimerJobsRunnable : starting to acquire async jobs due
-o.f.j.s.i.a.ResetExpiredJobsRunnable : starting to reset expired jobs
-o.f.e.impl.cmd.ValidateV5EntitiesCmd : Total of v5 deployments found: 0
-s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@4fdfa676: startup date [Wed Mar 28 12:04:00 CEST 2018]; root of context hierarchy
-s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(jakarta.servlet.http.HttpServletRequest)
-s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(jakarta.servlet.http.HttpServletRequest,jakarta.servlet.http.HttpServletResponse)
-o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
-o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
-o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
-o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
-o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure
-o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
-o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -20
-o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
-o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 20
-o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
-flowable.Application : Started Application in 18.235 seconds (JVM running for 19.661)
-----
-
-只是在classpath中添加依赖,并使用__@SpringBootAplication__注解,就会在幕后发生很多事情:
-
-* 自动创建了内存数据库(因为classpath中有H2驱动),并传递给Flowable流程引擎配置
-* 创建并暴露了Flowable的ProcessEngine、CmmnEngine、DmnEngine、FormEngine、ContentEngine及IdmEngine bean
-* 所有的Flowable服务都暴露为Spring bean
-* 创建了Spring Job Executor
-
-并且:
-
-* __processes__目录下的任何BPMN 2.0流程定义都会被自动部署。创建__processes__目录,并在其中创建示例流程定义(命名为__one-task-process.bpmn20.xml__)。
-* __cases__目录下的任何CMMN 1.1事例都会被自动部署。
-* __forms__目录下的任何Form定义都会被自动部署。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-然后添加下列代码,以测试部署是否生效。__CommandLineRunner__是一个特殊的Spring bean,在应用启动时执行:
-
-[source,java,linenums]
-----
-@SpringBootApplication(proxyBeanMethods = false)
-public class MyApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(MyApplication.class, args);
- }
-
- @Bean
- public CommandLineRunner init(final RepositoryService repositoryService,
- final RuntimeService runtimeService,
- final TaskService taskService) {
-
- return new CommandLineRunner() {
- @Override
- public void run(String... strings) throws Exception {
- System.out.println("Number of process definitions : "
- + repositoryService.createProcessDefinitionQuery().count());
- System.out.println("Number of tasks : " + taskService.createTaskQuery().count());
- runtimeService.startProcessInstanceByKey("oneTaskProcess");
- System.out.println("Number of tasks after process start: "
- + taskService.createTaskQuery().count());
- }
- };
- }
-}
-----
-
-会得到这样的输出:
-
-----
-Number of process definitions : 1
-Number of tasks : 0
-Number of tasks after process start : 1
-----
-
-[[_changing_the_database_and_connection_pool]]
-==== 更换数据源与连接池
-
-上面也提到过,Spring Boot的约定大于配置。默认情况下,如果classpath中只有H2,就会创建内存数据库,并传递给Flowable流程引擎配置。
-
-只要添加一个数据库驱动的依赖并提供数据库URL,就可以更换数据源。例如,要切换到MySQL数据库:
-
-[source,linenums]
-----
-spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable-spring-boot?characterEncoding=UTF-8
-spring.datasource.username=flowable
-spring.datasource.password=flowable
-----
-
-从Maven依赖中移除H2,并在classpath中添加MySQL驱动:
-
-[source,xml,linenums]
-----
-
- mysql
- mysql-connector-java
- 5.1.45
-
-----
-
-这次应用启动后,可以看到使用了MySQL作为数据库(并使用HikariCP连接池框架):
-
-----
-org.flowable.engine.impl.db.DbSqlSession : performing create on engine with resource org/flowable/db/create/flowable.mysql.create.engine.sql
-org.flowable.engine.impl.db.DbSqlSession : performing create on history with resource org/flowable/db/create/flowable.mysql.create.history.sql
-org.flowable.engine.impl.db.DbSqlSession : performing create on identity with resource org/flowable/db/create/flowable.mysql.create.identity.sql
-----
-
-多次重启应用,会发现任务的数量增加了(H2内存数据库在关闭后会丢失,而MySQL不会)。
-
-关于配置数据源的更多信息,可以在Spring Boot的参考手册中link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-configure-datasource$$[Configure a DataSource(配置数据源)]章节查看。
-
-[[_rest_support]]
-==== REST 支持
-
-通常会在嵌入的Flowable引擎之上,使用REST API(用于与公司的不同服务交互)。Spring Boot让这变得很容易。在classpath中添加下列依赖:
-
-[source,xml,linenums]
-----
-
- org.springframework.boot
- spring-boot-starter-web
- ${spring.boot.version}
-
-----
-
-创建一个新的Spring服务类,并创建两个方法:一个用于启动流程,另一个用于获得给定任务办理人的任务列表。在这里只是简单地包装了Flowable调用,但在实际使用场景中会比这复杂得多。
-
-
-[source,java,linenums]
-----
-@Service
-public class MyService {
-
- @Autowired
- private RuntimeService runtimeService;
-
- @Autowired
- private TaskService taskService;
-
- @Transactional
- public void startProcess() {
- runtimeService.startProcessInstanceByKey("oneTaskProcess");
- }
-
- @Transactional
- public List getTasks(String assignee) {
- return taskService.createTaskQuery().taskAssignee(assignee).list();
- }
-
-}
-----
-
-现在可以用__@RestController__来注解类,以创建REST endpoint。在这里我们简单地调用上面定义的服务。
-
-[source,java,linenums]
-----
-@RestController
-public class MyRestController {
-
- @Autowired
- private MyService myService;
-
- @PostMapping(value="/process")
- public void startProcessInstance() {
- myService.startProcess();
- }
-
- @RequestMapping(value="/tasks", method= RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
- public List getTasks(@RequestParam String assignee) {
- List tasks = myService.getTasks(assignee);
- List dtos = new ArrayList();
- for (Task task : tasks) {
- dtos.add(new TaskRepresentation(task.getId(), task.getName()));
- }
- return dtos;
- }
-
- static class TaskRepresentation {
-
- private String id;
- private String name;
-
- public TaskRepresentation(String id, String name) {
- this.id = id;
- this.name = name;
- }
-
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
-
- }
-
-}
-----
-
-Spring Boot会自动扫描组件,并找到我们添加在应用类上的__@Service__与__@RestController__。再次运行应用,现在可以与REST API交互了。例如使用cURL:
-
-
-----
-curl http://localhost:8080/tasks?assignee=kermit
-[]
-
-curl -X POST http://localhost:8080/process
-curl http://localhost:8080/tasks?assignee=kermit
-[{"id":"10004","name":"my task"}]
-----
-
-[[_jpa_support]]
-==== JPA 支持
-
-要为Spring Boot中的Flowable添加JPA支持,增加下列依赖:
-
-[source,xml,linenums]
-----
-
- org.flowable
- flowable-spring-boot-starter
- ${flowable.version}
-
-
- org.springframework.boot
- spring-boot-starter-data-jpa
- ${spring-boot.version
-
-----
-
-这会加入JPA用的Spring配置以及bean。默认使用Hibernate作为JPA提供者。
-
-创建一个简单的实体类:
-
-[source,java,linenums]
-----
-@Entity
-class Person {
-
- @Id
- @GeneratedValue
- private Long id;
-
- private String username;
-
- private String firstName;
-
- private String lastName;
-
- private Date birthDate;
-
- public Person() {
- }
-
- public Person(String username, String firstName, String lastName, Date birthDate) {
- this.username = username;
- this.firstName = firstName;
- this.lastName = lastName;
- this.birthDate = birthDate;
- }
-
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
- public Date getBirthDate() {
- return birthDate;
- }
-
- public void setBirthDate(Date birthDate) {
- this.birthDate = birthDate;
- }
-}
-----
-
-默认情况下,如果没有使用内存数据库则不会自动创建数据库表。在classpath中创建__application.properties__文件并加入下列参数:
-
-----
-spring.jpa.hibernate.ddl-auto=update
-----
-
-添加下列类:
-
-[source,java,linenums]
-----
-@Repository
-public interface PersonRepository extends JpaRepository {
-
- Person findByUsername(String username);
-}
-----
-
-这是一个Spring repository,提供了直接可用的增删改查。我们添加了通过username查找Person的方法。Spring会基于约定自动实现它(也就是使用names属性)。
-
-现在进一步增强我们的服务:
-
-* 在类上添加__@Transactional__。请注意,通过上面添加的JPA依赖,之前使用的DataSourceTransactionManager会自动替换为JpaTransactionManager。
-* __startProcess__增加了任务办理人入参,用于查找Person,并将Person JPA对象作为流程变量存入流程实例。
-* 添加了创建示例用户的方法。CommandLineRunner使用它打桩数据库。
-
-[source,java,linenums]
-----
-@Service
-@Transactional
-public class MyService {
-
- @Autowired
- private RuntimeService runtimeService;
-
- @Autowired
- private TaskService taskService;
-
- @Autowired
- private PersonRepository personRepository;
-
- public void startProcess(String assignee) {
-
- Person person = personRepository.findByUsername(assignee);
-
- Map variables = new HashMap();
- variables.put("person", person);
- runtimeService.startProcessInstanceByKey("oneTaskProcess", variables);
- }
-
- public List getTasks(String assignee) {
- return taskService.createTaskQuery().taskAssignee(assignee).list();
- }
-
- public void createDemoUsers() {
- if (personRepository.findAll().size() == 0) {
- personRepository.save(new Person("jbarrez", "Joram", "Barrez", new Date()));
- personRepository.save(new Person("trademakers", "Tijs", "Rademakers", new Date()));
- }
- }
-
-}
-----
-
-CommandLineRunner现在为:
-
-[source,java,linenums]
-----
-@Bean
-public CommandLineRunner init(final MyService myService) {
-
- return new CommandLineRunner() {
- public void run(String... strings) throws Exception {
- myService.createDemoUsers();
- }
- };
-}
-----
-
-RestController也有小改动(只展示新方法),以配合上面的修改。HTTP POST使用body传递办理人用户名:
-
-[source,java,linenums]
-----
-@RestController
-public class MyRestController {
-
- @Autowired
- private MyService myService;
-
- @PostMapping(value="/process")
- public void startProcessInstance(@RequestBody StartProcessRepresentation startProcessRepresentation) {
- myService.startProcess(startProcessRepresentation.getAssignee());
- }
-
- ...
-
- static class StartProcessRepresentation {
-
- private String assignee;
-
- public String getAssignee() {
- return assignee;
- }
-
- public void setAssignee(String assignee) {
- this.assignee = assignee;
- }
- }
-----
-
-最后,为了试用Spring-JPA-Flowable集成,我们在流程定义中,将Person JPA对象的ID指派为任务办理人:
-
-[source,xml,linenums]
-----
-
-----
-
-现在可以在POST body中提供用户名,启动一个新的流程实例:
-
-----
-curl -H "Content-Type: application/json" -d '{"assignee" : "jbarrez"}' http://localhost:8080/process
-----
-
-可以使用Person id获取任务列表:
-
-----
-curl http://localhost:8080/tasks?assignee=1
-
-[{"id":"12505","name":"my task"}]
-----
-
-[[springBootActuatorEndpoint]]
-==== Flowable Actuator Endpoint
-
-Flowable提供了Spring Boot Actuator Endpoint,以提供正在运行的流程的信息。
-默认情况下 `flowable` 端点映射至 `/actuator/flowable` 。
-Spring Boot默认只通过web暴露少许端点(例如:在 `spring-boot-starter-actuator:2.5.4` 中, Spring Boot 默认只通过web暴露了 `health` 端点。更多有关于 Spring Boot 默认暴露的端点的信息,请参考 link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.exposing$$[https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.exposing] )。要通过web使用 `flowable` 端点,需要在 `application.properties` 中添加 `management.endpoints.web.exposure.include=flowable` (注意: `org.flowable.spring.boot.EndpointAutoConfiguration` 类没有使用 `@ConditionalOnAvailableEndpoint` 注解检查 `flowable` 的端点是否同时被启用和被暴露。所以为了通过web使用 `flowable` 端点,你只需要在配置文件中添加 `management.endpoints.web.exposure.include=flowable` 或 `management.endpoints.web.exposure.include=*` 即可)。
-
-`curl http://localhost:8080/actuator/flowable`
-
-[source,json]
-----
-
-{
- "completedTaskCountToday": 0,
- "deployedProcessDefinitions": [
- "oneTaskProcess (v1)"
- ],
- "processDefinitionCount": 1,
- "cachedProcessDefinitionCount": 0,
- "runningProcessInstanceCount": {
- "oneTaskProcess (v1)": 0
- },
- "completedTaskCount": 2,
- "completedActivities": 3,
- "completedProcessInstanceCount": {
- "oneTaskProcess (v1)": 0
- },
- "openTaskCount": 0
-}
-----
-
-
-要了解Spring Boot Actuator的更多信息,可以在Spring Boot参考手册中查看link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html$$[Production Ready Endpoint(生产可用的端点)]。
-
-[[springBootInfoContributor]]
-==== Flowable Info Contributor
-
-Flowable也提供了Spring Boot的 `InfoContributor` :
-
-`curl http://localhost:8080/actuator/info`
-
-[source,json]
-----
-{
- "flowable": {
- "version": "6.3.0.1"
- }
-}
-----
-
-[[springBootFlowableProperties]]
-==== 配置Flowable应用
-
-Flowable会自动配置用于控制Spring Boot的参数与配置。参见Spring Boot参考手册中的link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html$$[Properties and Configuration(参数与配置)]。
-
-下面是Flowable Spring Boot支持的配置参数列表。
-
-[source,properties,indent=0,subs="verbatim,attributes,macros"]
-----
-
-# ===================================================================
-# Common Flowable Spring Boot Properties
-# 通用Flowable Spring Boot参数
-#
-# This sample file is provided as a guideline. Do NOT copy it in its
-# entirety to your own application. ^^^
-# 本示例文件只作为指导。请不要直接拷贝至你自己的应用中。
-# ===================================================================
-
-# Core (Process) {sc-flowable-boot}/FlowableProperties.java[FlowableProperties]
-# 核心(流程)
-flowable.check-process-definitions=true # 是否需要自动部署流程定义。
-flowable.custom-mybatis-mappers= # 需要添加至引擎的自定义Mybatis映射的FQN。
-flowable.custom-mybatis-x-m-l-mappers= # 需要添加至引擎的自定义Mybatis XML映射的路径。
-flowable.database-schema= # 如果数据库返回的元数据不正确,可以在这里设置schema用于检测/生成表。
-flowable.database-schema-update=true # 数据库schema更新策略。
-flowable.db-history-used=true # 是否要使用db历史。
-flowable.deployment-name=SpringBootAutoDeployment # 自动部署的名称。
-flowable.history-level=audit # 要使用的历史级别。
-flowable.process-definition-location-prefix=classpath*:/processes/ # 自动部署时查找流程的目录。
-flowable.process-definition-location-suffixes=**.bpmn20.xml,**.bpmn # 'processDefinitionLocationPrefix'路径下需要部署的文件的后缀(扩展名)。
-
-# Process {sc-flowable-boot}/process/FlowableProcessProperties.java[FlowableProcessProperties]
-# 流程
-flowable.process.definition-cache-limit=-1 # 流程定义缓存中保存流程定义的最大数量。默认值为-1(缓存所有流程定义)。
-flowable.process.enable-safe-xml=true # 在解析BPMN XML文件时进行额外检查。参见 https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml 。不幸的是,部分平台(JDK 6,JBoss)上无法使用这个功能,因此如果你所用的平台在XML解析时不支持StaxSource,需要禁用这个功能。
-flowable.process.servlet.load-on-startup=-1 # 启动时加载Process servlet。
-flowable.process.servlet.name=Flowable BPMN Rest API # Process servlet的名字。
-flowable.process.servlet.path=/process-api # Process servelet的context path。
-
-# Process Async Executor
-# 流程异步执行器
-flowable.process.async-executor-activate=true # 是否启用异步执行器。
-flowable.process.async.executor.async-job-lock-time-in-millis=300000 # 异步作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。
-flowable.process.async.executor.default-async-job-acquire-wait-time-in-millis=10000 # 异步作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的异步作业,或者只取到很少的异步作业时生效。默认值 = 10秒。
-flowable.process.async.executor.default-queue-size-full-wait-time-in-millis=0 # 异步作业(包括定时器作业与异步执行)获取线程在队列满时,等待执行下次查询的等待时间(以毫秒计)。默认值为0(以向后兼容)
-flowable.process.async.executor.default-timer-job-acquire-wait-time-in-millis=10000 # 定时器作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的定时器作业,或者只取到很少的定时器作业时生效。默认值 = 10秒。
-flowable.process.async.executor.max-async-jobs-due-per-acquisition=1 # (译者补)单次查询的异步作业数量。默认值为1,以降低乐观锁异常的可能性。除非你知道自己在做什么,否则请不要修改这个值。
-flowable.process.async.executor.retry-wait-time-in-millis=500 # ???(译者补不了了)
-flowable.process.async.executor.timer-lock-time-in-millis=300000 # 定时器作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。
-
-
-# CMMN {sc-flowable-boot}/cmmn/FlowableCmmnProperties.java[FlowableCmmnProperties]
-flowable.cmmn.deploy-resources=true # 是否部署资源。默认值为'true'。
-flowable.cmmn.deployment-name=SpringBootAutoDeployment # CMMN资源部署的名字。
-flowable.cmmn.enable-safe-xml=true # 在解析CMMN XML文件时进行额外检查。参见 https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml 。不幸的是,部分平台(JDK 6,JBoss)上无法使用这个功能,因此如果你所用的平台在XML解析时不支持StaxSource,需要禁用这个功能。
-flowable.cmmn.enabled=true # 是否启用CMMN引擎。
-flowable.cmmn.resource-location=classpath*:/cases/ # CMMN资源的路径。
-flowable.cmmn.resource-suffixes=**.cmmn,**.cmmn11,**.cmmn.xml,**.cmmn11.xml # 需要扫描的资源后缀名。
-flowable.cmmn.servlet.load-on-startup=-1 # 启动时加载CMMN servlet。
-flowable.cmmn.servlet.name=Flowable CMMN Rest API # CMMN servlet的名字。
-flowable.cmmn.servlet.path=/cmmn-api # CMMN servlet的context path。
-
-# CMMN Async Executor
-# CMMN异步执行器
-flowable.cmmn.async-executor-activate=true # 是否启用异步执行器。
-flowable.cmmn.async.executor.async-job-lock-time-in-millis=300000 # 异步作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。
-flowable.cmmn.async.executor.default-async-job-acquire-wait-time-in-millis=10000 # 异步作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的异步作业,或者只取到很少的异步作业时生效。默认值 = 10秒。
-flowable.cmmn.async.executor.default-queue-size-full-wait-time-in-millis=0 # 异步作业(包括定时器作业与异步执行)获取线程在队列满时,等待执行下次查询的等待时间(以毫秒计)。默认值为0(以向后兼容)
-flowable.cmmn.async.executor.default-timer-job-acquire-wait-time-in-millis=10000 # 定时器作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的定时器作业,或者只取到很少的定时器作业时生效。默认值 = 10秒。
-flowable.cmmn.async.executor.max-async-jobs-due-per-acquisition=1 # (译者补)单次查询的异步作业数量。默认值为1,以降低乐观锁异常的可能性。除非你知道自己在做什么,否则请不要修改这个值。
-flowable.cmmn.async.executor.retry-wait-time-in-millis=500 #(译者补不了了)
-flowable.cmmn.async.executor.timer-lock-time-in-millis=300000 # 定时器作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。
-
-# Content {sc-flowable-boot}/content/FlowableContentProperties.java[FlowableContentProperties]
-flowable.content.enabled=true # 是否启动Content引擎。
-flowable.content.servlet.load-on-startup=-1 # 启动时加载Content servlet。
-flowable.content.servlet.name=Flowable Content Rest API # Content servlet的名字。
-flowable.content.servlet.path=/content-api # Content servlet的context path。
-flowable.content.storage.create-root=true # 如果根路径不存在,是否需要创建?
-flowable.content.storage.root-folder= # 存储content文件(如上传的任务附件,或表单文件)的根路径。
-
-# DMN {sc-flowable-boot}/dmn/FlowableDmnProperties.java[FlowableDmnProperties]
-flowable.dmn.deploy-resources=true # 是否部署资源。默认为'true'。
-flowable.dmn.deployment-name=SpringBootAutoDeployment # DMN资源部署的名字。
-flowable.dmn.enable-safe-xml=true # 在解析DMN XML文件时进行额外检查。参见 https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml 。不幸的是,部分平台(JDK 6,JBoss)上无法使用这个功能,因此如果你所用的平台在XML解析时不支持StaxSource,需要禁用这个功能。
-flowable.dmn.enabled=true # 是否启用DMN引擎。
-flowable.dmn.history-enabled=true # 是否启用DMN引擎的历史。
-flowable.dmn.resource-location=classpath*:/dmn/ # DMN资源的路径。
-flowable.dmn.resource-suffixes=**.dmn,**.dmn.xml,**.dmn11,**.dmn11.xml # 需要扫描的资源后缀名。
-flowable.dmn.servlet.load-on-startup=-1 # 启动时加载DMN servlet。
-flowable.dmn.servlet.name=Flowable DMN Rest API # DMN servlet的名字。
-flowable.dmn.servlet.path=/dmn-api # DMN servlet的context path。
-flowable.dmn.strict-mode=true # 如果希望避免抉择表命中策略检查导致失败,可以将本参数设置为false。如果检查发现了错误,会直接返回错误前一刻的中间结果。
-
-# Form {sc-flowable-boot}/form/FlowableFormProperties.java[FlowableFormProperties]
-flowable.form.deploy-resources=true # 是否部署资源。默认为'true'。
-flowable.form.deployment-name=SpringBootAutoDeployment # Form资源部署的名字。
-flowable.form.enabled=true # 是否启用Form引擎。
-flowable.form.resource-location=classpath*:/forms/ # Form资源的路径。
-flowable.form.resource-suffixes=**.form # 需要扫描的资源后缀名。
-flowable.form.servlet.load-on-startup=-1 # 启动时加载Form servlet。
-flowable.form.servlet.name=Flowable Form Rest API # Form servlet的名字。
-flowable.form.servlet.path=/form-api # Form servlet的context path。
-
-# IDM {sc-flowable-boot}/idm/FlowableIdmProperties.java[FlowableIdmProperties]
-flowable.idm.enabled=true # 是否启用IDM引擎。
-flowable.idm.password-encoder= # 使用的密码编码类型。
-flowable.idm.servlet.load-on-startup=-1 # 启动时加载IDM servlet。
-flowable.idm.servlet.name=Flowable IDM Rest API # IDM servlet的名字。
-flowable.idm.servlet.path=/idm-api # IDM servlet的context path。
-
-# IDM Ldap {sc-flowable-boot}/ldap/FlowableLdapProperties.java[FlowableLdapProperties]
-flowable.idm.ldap.attribute.email= # 用户email的属性名。
-flowable.idm.ldap.attribute.first-name= # 用户名字的属性名。
-flowable.idm.ldap.attribute.group-id= # 用户组ID的属性名。
-flowable.idm.ldap.attribute.group-name= # 用户组名的属性名。
-flowable.idm.ldap.attribute.group-type= # 用户组类型的属性名。
-flowable.idm.ldap.attribute.last-name= # 用户姓的属性名。
-flowable.idm.ldap.attribute.user-id= # 用户ID的属性名。
-flowable.idm.ldap.base-dn= # 查找用户与组的DN(标志名称 distinguished name)。
-flowable.idm.ldap.cache.group-size=-1 # 设置{@link org.flowable.ldap.LDAPGroupCache}的大小。这是LRU缓存,用于缓存用户及组,以避免每次都查询LDAP系统。
-flowable.idm.ldap.custom-connection-parameters= # 用于设置所有没有专用setter的LDAP连接参数。查看 http://docs.oracle.com/javase/tutorial/jndi/ldap/jndi.html 介绍的自定义参数。参数包括配置链接池,安全设置,等等。
-flowable.idm.ldap.enabled=false # 是否启用LDAP IDM 服务。
-flowable.idm.ldap.group-base-dn= # 组查找的DN。
-flowable.idm.ldap.initial-context-factory=com.sun.jndi.ldap.LdapCtxFactory # 初始化上下文工厂的类名。
-flowable.idm.ldap.password= # 连接LDAP系统的密码。
-flowable.idm.ldap.port=-1 # LDAP系统的端口。
-flowable.idm.ldap.query.all-groups= # 查询所有组所用的语句。
-flowable.idm.ldap.query.all-users= # 查询所有用户所用的语句。
-flowable.idm.ldap.query.groups-for-user= # 按照指定用户查询所属组所用的语句
-flowable.idm.ldap.query.user-by-full-name-like= # 按照给定全名查找用户所用的语句。
-flowable.idm.ldap.query.user-by-id= # 按照userId查找用户所用的语句。
-flowable.idm.ldap.search-time-limit=0 # 查询LDAP的超时时间(以毫秒计)。默认值为'0',即“一直等待”。
-flowable.idm.ldap.security-authentication=simple # 连接LDAP系统所用的'java.naming.security.authentication'参数的值。
-flowable.idm.ldap.server= # LDAP系统的主机名。如'ldap://localhost'。
-flowable.idm.ldap.user= # 连接LDAP系统的用户ID。
-flowable.idm.ldap.user-base-dn= # 查找用户的DN。
-
-# Flowable Mail {sc-flowable-boot}/FlowableMailProperties.java[FlowableMailProperties]
-flowable.mail.server.default-from=flowable@localhost # 发送邮件时使用的默认发信人地址。
-flowable.mail.server.host=localhost # 邮件服务器。
-flowable.mail.server.password= # 邮件服务器的登录密码。
-flowable.mail.server.port=1025 # 邮件服务器的端口号。
-flowable.mail.server.ssl-port=1465 # SSL邮件服务器的端口号。
-flowable.mail.server.use-ssl=false # 是否使用SSL/TLS加密SMTP传输连接(即SMTPS/POPS)。
-flowable.mail.server.use-tls=false # 使用或禁用STARTTLS加密。
-flowable.mail.server.username= # 邮件服务器的登录用户名。如果为空,则不需要登录。
-
-# Flowable Http {sc-flowable-boot}/FlowableHttpProperties.java[FlowableHttpProperties]
-flowable.http.user-system-properties=false # 是否使用系统属性 (e.g. http.proxyPort).
-flowable.http.connect-timeout=5s # 连接http客户端的超时时间
-flowable.http.socket-timeout=5s # http客户端的Socket超时时间
-flowable.http.connection-request-timeout=5s # http客户端的连接请求超时时间
-flowable.http.request-retry-limit=3 # 请求http客户端的重试限制
-flowable.http.disable-cert-verify=false # 是否禁用http客户端的证书验证
-
-# Flowable REST
-flowable.rest.app.cors.enabled=true # Whether to enable CORS requests at all. If false, the other properties have no effect
-flowable.rest.app.cors.allow-credentials=true # Whether to include credentials in a CORS request
-flowable.rest.app.cors.allowed-origins=* # Comma-separated URLs to accept CORS requests from
-flowable.rest.app.cors.allowed-headers=* # Comma-separated HTTP headers to allow in a CORS request
-flowable.rest.app.cors.allowed-methods=DELETE,GET,PATCH,POST,PUT # Comma-separated HTTP verbs to allow in a CORS request
-flowable.rest.app.cors.exposed-headers=* # Comma-separated list of headers to expose in CORS response
-
-# Actuator
-management.endpoint.flowable.cache.time-to-live=0ms # 缓存响应的最大时间。
-management.endpoint.flowable.enabled=true # 是否启用flowable端点。
-
-----
-
-
-.弃用的参数
-[cols="4*",options="header"]
-|===============
-|现参数
-|原参数
-|默认值
-|描述
-
-|flowable.process.servlet.name
-|flowable.rest-api-servlet-name
-|Flowable BPMN Rest API
-|Process servlet的名字。
-
-|flowable.process.servlet.path
-|flowable.rest-api-mapping
-|/process-api
-|Process servlet的context path。
-
-|flowable.mail.server.host
-|flowable.mail-server-host
-|localhost
-|邮件服务器。
-
-|flowable.mail.server.password
-|flowable.mail-server-password
-|-
-|邮件服务器的密码。
-
-|flowable.mail.server.port
-|flowable.mail-server-port
-|1025
-|邮件服务器的端口号。
-
-|flowable.mail.server.ssl-port
-|flowable.mail-server-ssl-port
-|1465
-|SSL邮件服务器的端口号。
-
-|flowable.mail.server.use-ssl
-|flowable.mail-server-use-ssl
-|false
-|是否使用SSL/TLS加密SMTP传输连接(即SMTPS/POPS)。
-
-|flowable.mail.server.use-tls
-|flowable.mail-server-use-tls
-|false
-|使用或禁用STARTTLS加密。
-
-|flowable.mail.server.username
-|flowable.mail-server-user-name
-|-
-|邮件服务器的登录用户名。如果为空,则不需要登录。
-
-|flowable.process.definition-cache-limit
-|flowable.process-definitions.cache.max
-|-1
-|流程定义缓存中保存流程定义的最大数量。默认值为-1(缓存所有流程定义)。
-|===============
-
-[[springBootFlowableAutoConfiguration]]
-==== Flowable自动配置类
-
-这是Flowable提供的所有自动配置类的列表,并包括了文档及源码的连接。记得查看你的应用的conditions报告,以确认具体启用了哪些功能。(使用--debug或-Ddebug或在Actuator应用中启动应用,并使用 `conditions` 端点)。
-
-[cols=*,options="header"]
-|===
-|配置类
-
-|{sc-flowable-boot}/content/ContentEngineAutoConfiguration.java[ContentEngineAutoConfiguration]
-|{sc-flowable-boot}/content/ContentEngineServicesAutoConfiguration.java[ContentEngineServicesAutoConfiguration]
-|{sc-flowable-boot}/cmmn/CmmnEngineAutoConfiguration.java[CmmnEngineAutoConfiguration]
-|{sc-flowable-boot}/cmmn/CmmnEngineServicesAutoConfiguration.java[CmmnEngineServicesAutoConfiguration]
-|{sc-flowable-boot}/dmn/DmnEngineAutoConfiguration.java[DmnEngineAutoConfiguration]
-|{sc-flowable-boot}/dmn/DmnEngineServicesAutoConfiguration.java[DmnEngineServicesAutoConfiguration]
-|{sc-flowable-boot}/EndpointAutoConfiguration.java[EndpointAutoConfiguration]
-|{sc-flowable-boot}/actuate/info/FlowableInfoAutoConfiguration.java[FlowableInfoAutoConfiguration]
-|{sc-flowable-boot}/ldap/FlowableLdapAutoConfiguration.java[FlowableLdapAutoConfiguration]
-|{sc-flowable-boot}/FlowableTransactionAutoConfiguration.java[FlowableTransactionAutoConfiguration]
-|{sc-flowable-boot}/form/FormEngineAutoConfiguration.java[FormEngineAutoConfiguration]
-|{sc-flowable-boot}/form/FormEngineServicesAutoConfiguration.java[FormEngineServicesAutoConfiguration]
-|{sc-flowable-boot}/idm/IdmEngineAutoConfiguration.java[IdmEngineAutoConfiguration]
-|{sc-flowable-boot}/idm/IdmEngineServicesAutoConfiguration.java[IdmEngineServicesAutoConfiguration]
-|{sc-flowable-boot}/ProcessEngineAutoConfiguration.java[ProcessEngineAutoConfiguration]
-|{sc-flowable-boot}/RestApiAutoConfiguration.java[RestApiAutoConfiguration]
-|{sc-flowable-boot}/SecurityAutoConfiguration.java[SecurityAutoConfiguration]
-
-|===
-
-[[springBootFlowableStarter]]
-==== Flowable Starter
-
-这是Flowable Spring Boot stater的列表。
-
-[cols=2*,options="header"]
-|===
-|Starter
-|描述
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-cmmn/pom.xml[flowable-spring-boot-starter-cmmn]
-|提供以独立运行模式启动CMMN引擎的依赖
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-cmmn-rest/pom.xml[flowable-spring-boot-starter-cmmn-rest]
-|提供以独立运行模式启动CMMN引擎,并提供其REST API的依赖。
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-dmn/pom.xml[flowable-spring-boot-starter-dmn]
-|提供以独立运行模式启动DMN引擎的依赖。
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-dmn-rest/pom.xml[flowable-spring-boot-starter-dmn-rest]
-|提供以独立运行模式启动DMN引擎,并提供其REST API的依赖。
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-process/pom.xml[flowable-spring-boot-starter-process]
-|提供以独立运行模式启动流程引擎的依赖。
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-process-rest/pom.xml[flowable-spring-boot-starter-process-rest]
-|提供以独立运行模式启动流程引擎,并提供其REST API的依赖。
-
-|{sc-flowable-starter}/flowable-spring-boot-starter/pom.xml[flowable-spring-boot-starter]
-|提供启动所有Flowable引擎(流程,CMMN,DMN,Form,Content及IDM)的依赖。
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-rest/pom.xml[flowable-spring-boot-starter-rest]
-|提供启动所有Flowable引擎,并提供其REST API的依赖。
-
-|{sc-flowable-starter}/flowable-spring-boot-starter-actuator/pom.xml[flowable-spring-boot-starter-actuator]
-|提供Spring Boot Actuator所需的依赖。
-
-|===
-
-
-[[_using_liquibase]]
-==== 使用Liquibase
-
-Flowable引擎使用Liquibase管理数据库版本。
-因此Spring Boot的 `LiquibaseAutoConfiguration` 会自动启用。
-然而,如果你并未使用Liquibase,则应用将无法启动,并抛出异常。
-因此Flowable将 `spring.liquibase.enabled` 设置为 `false` ,也即如果需要使用Liquibase,则需手动启用它。
-
-[[_further_reading]]
-==== 扩展阅读
-
-很明显还有很多Spring Boot相关的内容还没有提及,如非常简单的JTA集成、构建能在主流应用服务器上运行的WAR文件。也还有很多Spring Boot集成:
-
-* Actuator支持
-* Spring Integration支持
-* Rest API集成:启动Spring应用中嵌入的Flowable Rest API
-* Spring Security支持
-
-[[_advanced_configuration]]
-==== 高级配置
-
-[[_customizing_engine_configuration]]
-===== 自定义引擎配置
-
-实现__org.flowable.spring.boot.EngineConfigurationConfigurer__接口,可以获取引擎配置对象。其中__T__是具体引擎配置的Spring类型。
-这样可以在参数尚未公开时,进行高级配置,或简化配置。
-例如:
-
-[source, java, linenums]
-----
-public class MyConfigurer implements EngineConfigurationConfigurer {
-
- public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
- // advanced configuration
- }
-
-}
-----
-
-在Spring Boot配置中使用__@Bean__发布该类的实例,这样配置类会在流程引擎创建前调用。
-
-[TIP]
-====
-可以用这种方法实现自定义的Flowable服务。参见 {sc-flowable-boot}/ldap/FlowableLdapAutoConfiguration.java[FlowableLdapAutoConfiguration]
-====
-
-[[_combining_starters]]
-===== 整合starter
-
-如果需要一组引擎,则只能依次添加依赖。
-比如要使用流程、CMMN、Form与IDM引擎,并使用LDAP,则需要添加这些依赖:
-
-[source,xml,linenums]
-----
-
- org.flowable
- flowable-spring-boot-starter-process
- ${flowable.version}
-
-
- org.flowable
- flowable-spring-boot-starter-cmmn
- ${flowable.version}
-
-
- org.flowable
- flowable-content-spring-configurator
- ${flowable.version}
-
-
- org.flowable
- flowable-ldap
- ${flowable.version}
-
-----
-
-[[_configuring_async_executors]]
-===== 配置异步执行器
-
-流程及CMMN引擎使用专门的 `AsyncExecutor` ,并可使用 `flowable.{engine}.async.executor` 参数组进行配置。
-其中 `engine` 代表 `process` 或 `cmmn` 。
-
-默认情况下, `AsyncExecutor` 共享同一个Spring `TaskExecutor` 及 `SpringRejectedJobsHandler` 。
-如果需要为引擎提供专门的执行器,则需要使用 `@Process` 及 `@Cmmn` 定义的bean。
-
-可以使用如下方法配置自定义的执行器:
-
-[source,java,linenums]
-----
-@Configuration
-public class MyConfiguration {
-
- @Process <1>
- @Bean
- public TaskExecutor processTaskExecutor() {
- return new SimpleAsyncTaskExecutor();
- }
-
- @Cmmn <2>
- @Bean
- public TaskExecutor cmmnTaskExecutor() {
- return new SyncTaskExecutor();
- }
-}
-----
-<1> 流程引擎将使用 `SimpleAsyncTaskExecutor` 作为异步执行器
-<2> CMMN引擎将使用 `SyncTaskExecutor` 作为异步执行器
-
-[IMPORTANT]
-======
-如果使用了自定义的 `TaskExecutor` bean,则Flowable将不会再创建自己的bean。
-也就是说如果使用 `@Process` 定义了bean,也需要使用 `@Cmmn` 或 `@Primary` 再定义一个bean。否则Cmmn异步执行器将使用流程引擎所用的bean。
-======
-
diff --git a/docs/userguide/src/zh_CN/bpmn/ch06-Deployment.adoc b/docs/userguide/src/zh_CN/bpmn/ch06-Deployment.adoc
deleted file mode 100755
index b5471ccd01f..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch06-Deployment.adoc
+++ /dev/null
@@ -1,205 +0,0 @@
-[[chDeployment]]
-
-== 部署
-
-[[_business_archives]]
-=== 业务存档
-
-要部署流程,需要将它们包装在业务存档(BAR, Business archive)里。业务存档是Flowable引擎的部署单元,也就是一个ZIP文件。可以包含BPMN 2.0流程、表单定义、DMN规则,与其他类型的文件。总的来说,业务存档包含一组具名资源。
-
-当部署业务存档时,会扫描具有++.bpmn20.xml++或++.bpmn++扩展名的BPMN文件。每一个这种文件都会被处理,并可以包含多个流程定义。
-当启用DMN引擎时,也会解析++.dmn++。当启用表单引擎时,会处理++.form++文件。
-
-[NOTE]
-====
-业务存档中的Java类**不会添加至classpath**。业务存档中,所有流程定义使用的自定义类(例如Java服务任务或者事件监听器),都需要放在运行流程的flowable引擎的classpath内。
-====
-
-[[_deploying_programmatically]]
-==== 编程方式部署
-
-从ZIP文件部署业务存档,可以这样做:
-
-[source,java,linenums]
-----
-String barFileName = "path/to/process-one.bar";
-ZipInputStream inputStream = new ZipInputStream(new FileInputStream(barFileName));
-
-repositoryService.createDeployment()
- .name("process-one.bar")
- .addZipInputStream(inputStream)
- .deploy();
-
-----
-
-也可以为单个资源构建部署。查看javadoc以获取更多信息。
-
-[[_external_resources]]
-=== 外部资源
-
-流程定义保存在Flowable数据库中。这些流程定义在使用服务任务、执行监听器,或执行Flowable配置文件中定义的Spring bean时,可以引用委托类。这些类及Spring配置文件都需要在可能运行这个流程定义的流程引擎中可用。
-
-[[_java_classes]]
-==== Java类
-
-在流程启动时,引擎的classpath中需要有所有流程中用到的自定义类(例如服务任务、事件监听器、任务监听器等中用到的JavaDelegate)。
-
-但是在部署业务存档时,classpath中可以没有这些类。这意味着,比如使用Ant部署新业务存档时,代理类不必提前放在classpath中。
-
-当使用演示配置且希望添加自定义类时,需要在flowable-task或flowable-rest的webapp lib中,添加包含有你的自定义类的JAR。别忘了也要添加你的自定义类的依赖(若有)。或者,也可以将你的依赖添加到Tomcat的库文件夹++${tomcat.home}/lib++中。
-
-[[_using_spring_beans_from_a_process]]
-==== 在流程中使用Spring bean
-
-在表达式或脚本中使用Spring bean时,执行该流程定义的引擎需要可以使用这些bean。可以简单直接地自行构建web应用,并按照<>章节的介绍在上下文中配置流程引擎。但也请牢记在心,如果使用Flowable task和rest web应用,就需要更新它的上下文配置。
-
-[[_creating_a_single_app]]
-==== 创建单独应用
-
-如果不想费心在所有流程引擎的classpath中都包含所有需要的代理类,及保证它们都使用了正确的Spring配置,也可以考虑将Flowable rest web应用嵌入你自己的web应用。也就是说只使用一个单独的++ProcessEngine++。
-
-
-[[versioningOfProcessDefinitions]]
-
-=== 流程定义的版本
-
-BPMN并没有版本的概念。这其实很好,因为可执行的BPMN流程文件很可能已经作为开发项目的一部分,保存在版本管理系统仓库中了(例如Subversion,Git,或者Mercurial)。但是,作为部署过程的一部分,引擎会创建流程定义的版本。在部署时,Flowable会在保存至Flowable数据库前,为++ProcessDefinition++指定版本。
-
-对于业务存档中的每个流程定义,为了初始化++key++、++version++、++name++与++id++参数,会执行下列步骤:
-
-* XML文件中的流程定义++id++属性用作流程定义的++key++参数。
-* XML文件中的流程定义++name++属性用作流程定义的++name++参数。如果未给定++name++属性,会使用id作为name。
-* 当每个key的流程第一次部署时,指定版本为1。对其后所有使用相同key的流程定义,部署时版本会在该key当前已部署的最高版本号基础上加1。key参数用于区分流程定义。
-* id参数设置为{processDefinitionKey}:{processDefinitionVersion}:{generated-id},其中++generated-id++是一个唯一数字,用以保证在集群环境下,流程定义缓存中,流程id的唯一性。
-
-以下面的流程为例
-
-[source,xml,linenums]
-----
-
-
- ...
-----
-
-当部署这个流程定义时,数据库中的流程定义会是这个样子:
-
-[options="header"]
-|===============
-|id|key|name|version
-|myProcess:1:676|myProcess|My important process|1
-
-|===============
-
-如果我们现在部署同一个流程的更新版本(例如修改部分用户任务),且保持流程定义的++id++不变,那么流程定义表中会包含下面的记录:
-
-
-[options="header"]
-|===============
-|id|key|name|version
-|myProcess:1:676|myProcess|My important process|1
-|myProcess:2:870|myProcess|My important process|2
-
-|===============
-
-当调用++runtimeService.startProcessInstanceByKey("myProcess")++时,会使用版本++2++的流程定义,因为这是这个流程定义的最新版本。
-
-如果再创建第二个流程,如下定义并部署至Flowable,表中会增加第三行。
-
-[source,xml,linenums]
-----
-
-
- ...
-----
-
-表数据类似:
-
-[options="header"]
-|===============
-|id|key|name|version
-|myProcess:1:676|myProcess|My important process|1
-|myProcess:2:870|myProcess|My important process|2
-|myNewProcess:1:1033|myNewProcess|My important process|1
-
-|===============
-
-请注意新流程的key与第一个流程的key不同。即使name是相同的(我们也可以修改它),Flowable也只用++id++属性来区分流程。因此新的流程部署时版本为1.
-
-
-[[providingProcessDiagram]]
-
-
-=== 提供流程图
-
-可以在部署中添加流程图片。这个图片将存储在Flowable数据库中,并可以使用API访问。图片可以用在Flowable应用中,使流程可视化。
-
-如果在classpath中,有一个++org/flowable/expenseProcess.bpmn20.xml++流程,key为'expense'。则流程图片会使用下列命名约定(按顺序):
-
-* 如果部署中有图片资源,并且文件名包含BPMN 2.0 XML流程定义文件名以及流程key,并具有图形格式,则使用这个图片。在我们的例子中,就是++org/flowable/expenseProcess.expense.png++(或者.jpg/gif)。使用key的原因是,一个BPMN 2.0 XML文件中可以有多个流程定义。因此使用流程key区分每一个流程图的文件。
-* 如果没有这种图片,就会寻找部署中匹配BPMN 2.0 XML文件名的图片资源。在我们的例子中,就是++org/flowable/expenseProcess.png++。请注意,这意味着同一个BPMN 2.0文件中的**每一个流程定义**,都会使用同一个流程图图片。当然,如果每个BPMN 2.0 XML文件中都只有一个流程定义,就没有问题。
-
-
-用编程方式部署的例子:
-
-[source,java,linenums]
-----
-
-repositoryService.createDeployment()
- .name("expense-process.bar")
- .addClasspathResource("org/flowable/expenseProcess.bpmn20.xml")
- .addClasspathResource("org/flowable/expenseProcess.png")
- .deploy();
-----
-
-
-图片资源可用下面的API获取:
-
-[source,java,linenums]
-----
-ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
- .processDefinitionKey("expense")
- .singleResult();
-
-String diagramResourceName = processDefinition.getDiagramResourceName();
-InputStream imageStream = repositoryService.getResourceAsStream(
- processDefinition.getDeploymentId(), diagramResourceName);
-----
-
-
-[[generatingProcessDiagram]]
-
-
-=== 生成流程图
-
-如果部署时没有按<>介绍的方式提供图片,且流程定义中包含必要的“图形交换(diagram interchange)”信息,Flowable引擎会生成流程图。
-
-可以用与部署时<>完全相同的方法获取图片资源。
-
-image::images/deployment.image.generation.png[align="center"]
-
-如果不需要或不希望在部署时生成流程图,可以在流程引擎配置中设置++isCreateDiagramOnDeploy++参数:
-
-[source,xml,linenums]
-----
-
-----
-
-这样就不会生成流程图了。
-
-[[deploymentCategory]]
-
-
-=== 类别
-
-部署与流程定义都可以自定义类别。流程定义的类别使用BPMN文件中targetNamespace的值设置:++++。
-
-部署的类别也可用API如此设定:
-
-[source,java,linenums]
-----
-repositoryService
- .createDeployment()
- .category("yourCategory")
- ...
- .deploy();
-----
diff --git a/docs/userguide/src/zh_CN/bpmn/ch07a-BPMN-Introduction.adoc b/docs/userguide/src/zh_CN/bpmn/ch07a-BPMN-Introduction.adoc
deleted file mode 100755
index ce048a058e9..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch07a-BPMN-Introduction.adoc
+++ /dev/null
@@ -1,421 +0,0 @@
-[[bpmn20]]
-
-== BPMN 2.0介绍
-
-[[whatIsBpmn]]
-
-
-=== BPMN是什么?
-
-BPMN是一个广泛接受与支持的,展现流程的注记方法。link:$$http://www.bpmn.org/$$[OMG BPMN标准].
-
-[[bpmnDefiningProcess]]
-
-
-=== 定义流程
-
-
-[NOTE]
-====
-本篇文档假设你使用link:$$http://eclipse.org/$$[Eclipse IDE]创建与编辑文件。但其实文档中只有少数几处使用了Eclipse的特性。你可以使用喜欢的任何其他工具创建BPMN 2.0 XML文件。
-
-====
-
-创建一个新的XML文件(__在任意项目上右击,选择New->Other->XML-XML File__)并命名。确保该文件名**以.bpmn20.xml或.bpmn结尾**,否则引擎不会在部署时使用这个文件。
-
-image::images/new.bpmn.procdef.png[align="center"]
-
-BPMN 2.0概要(schema)的根元素(root element)是++definitions++元素。在这个元素中,可以定义多个流程定义(然而我们建议在每个文件中,只有一个流程定义。这样可以简化之后的部署过程)。下面给出的是一个空流程定义。请注意++definitions++元素最少需要包含++xmlns++与++targetNamespace++声明。++targetNamespace++可以为空,它用于对流程定义进行分类。
-
-[source,xml,linenums]
-----
-
-
-
- ..
-
-
-
-----
-
-除了使用Eclipse中的XML分类选项,也可以使用在线概要作为BPMN 2.0 XML概要。
-
-
-[source,xml,linenums]
-----
-xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL
- http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd
-----
-
-
-++process++元素有两个属性:
-
-* *id*: **必填**属性,将映射为Flowable ++ProcessDefinition++对象的**key**参数。可以使用++RuntimeService++中的++startProcessInstanceByKey++方法,使用++id++来启动这个流程定义的新流程实例。这个方法总会使用流程定义的**最新部署版本**。
-
-
-[source,java,linenums]
-----
-ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
-----
-
-* 请注意这与调用++startProcessInstanceById++方法不同。++startProcessInstanceById++方法的参数为Flowable引擎在部署时生成的字符串ID(可以通过调用++processDefinition.getId()++方法获取)。生成ID的格式为**'key:version'**,长度**限制为64字符**。请注意限制流程__key__的长度,否则会抛出++FlowableException++异常,提示生成的ID过长。
-* *name*: **可选**属性,将映射为++ProcessDefinition++的__name__参数。引擎本身不会使用这个参数。可以用于在用户界面上显示更友好的名字。
-
-
-[[bpmn10minutetutorial]]
-
-
-=== 开始:十分钟教程
-
-这个章节包含了一个很简单的业务流程,用于介绍一些基本的Flowable概念以及Flowable API。
-
-
-[[bpmn10MinuteTutorialPrerequisites]]
-
-
-==== 必要条件
-
-这个教程需要你已经<>,并使用独立的H2服务器。编辑++db.properties++并设置++jdbc.url=jdbc:h2:tcp://localhost/flowable++,然后按照link:$$http://www.h2database.com/html/tutorial.html#using_server$$[H2文档]的介绍运行独立服务器。
-
-
-[[bpmn10MinuteTutorialGoal]]
-
-
-==== 目标
-
-这个教程的目标是学习Flowable以及BPMN 2.0的一些基础概念。最后成果是一个简单的Java SE程序,部署了一个流程定义,并可以通过Flowable引擎API与流程进行交互。当然,在这个教程里学到的东西,也可以按照你的业务流程用于构建你自己的web应用程序。
-
-
-[[bpmnFirstExampleUseCase]]
-
-
-==== 用例
-
-用例很简单:有一个公司,叫做BPMCorp。在BPMCorp中,由会计部门负责,每月需要为投资人撰写一份报告。在报告完成后,需要高层经理中的一人进行审核,然后才能发给所有投资人。
-
-
-[[bpmnFirstExampleDiagram]]
-
-
-==== 流程图
-
-上面描述的业务流程可以使用<>直接画出。但是在这个教程里我们自己写XML,这样可以学习更多。这个流程的图形化BPMN 2.0注记像是这样:
-
-image::images/financial.report.example.diagram.png[align="center"]
-
-我们看到的是一个<>(左边的圆圈),接下来是两个<>:__'Write monthly financial report(撰写月度财务报告)'__与__'Verify monthly financial report(审核月度财务报告)'__。最后是<>(右边的粗线条圆圈)。
-
-
-[[bpmnFirstExampleXml]]
-
-
-==== XML格式
-
-这个业务流程的XML版本(__FinancialReportProcess.bpmn20.xml__)在下面展示。很容易认出流程的主要元素(点击链接可以跳转到BPMN 2.0结构的详细章节):
-
-* <>是流程的__入口点(entry point)__。
-* <>表示流程中的人工任务。请注意第一个任务分配给__accountancy__组,而第二个任务分配给__management__组。查看<>章节了解更多关于用户与组如何分配用户任务的信息。
-* 流程在到达<>时结束。
-* 各元素间通过<>链接。顺序流用++source++ 与++target++定义顺序流的__流向(direction)__。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
- Write monthly financial report for publication to shareholders.
-
-
-
- accountancy
-
-
-
-
-
-
-
-
- Verify monthly financial report composed by the accountancy department.
- This financial report is going to be sent to all the company shareholders.
-
-
-
- management
-
-
-
-
-
-
-
-
-
-
-
-----
-
-
-[[bpmnFirstExamplStartProcess]]
-
-
-==== 启动流程实例
-
-现在我们已经创建了业务流程的**流程定义**。使用这样的流程定义,可以创建**流程实例**。在这个例子中,一个流程实例将对应某一月份的财经报告创建与审核工作。所有月份的流程实例共享相同的流程定义。
-
-要用给定的流程定义创建流程实例,需要首先**部署(deploy)**流程定义。部署流程定义意味着两件事:
-
-* 流程定义将会存储在Flowable引擎配置的持久化数据库中。因此部署业务流程保证了引擎在重启后也能找到流程定义。
-* BPMN 2.0流程XML会解析为内存中的对象模型,供Flowable API使用。
-
-更多关于部署的信息可以在<>章节中找到。
-
-与该章节的描述一样,部署有很多种方式。其中一种是通过下面展示的API。请注意所有与Flowable引擎的交互都要通过它的__服务(services)__进行。
-
-[source,java,linenums]
-----
-Deployment deployment = repositoryService.createDeployment()
- .addClasspathResource("FinancialReportProcess.bpmn20.xml")
- .deploy();
-----
-
-现在可以使用在流程定义中定义的++id++(参见XML中的process元素)启动新流程实例。请注意这个++id++在Flowable术语中被称作**key**。
-
-[source,java,linenums]
-----
-ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport");
-----
-
-这会创建流程实例,并首先通过开始事件。在开始事件后,会沿着所有出口顺序流(在这个例子中只有一个)继续执行,并到达第一个任务('write monthly financial report 撰写月度财务报告')。这时,Flowable引擎会在持久化数据库中存储一个任务。同时也会解析并保存这个任务附加的分配用户或组。请注意,Flowable引擎会持续执行流程,直到到达__等待状态(wait state)__,例如用户任务。在等待状态,流程实例的当前状态会存储在数据库中并保持,直到用户决定完成任务。这时,引擎会继续执行,直到遇到新的等待状态,或者流程结束。如果在这期间引擎重启或崩溃,流程的状态也仍在数据库中安全的保存。
-
-用户任务活动是一个__等待状态__,因此++startProcessInstanceByKey++方法会在任务创建后返回。在这个例子里,这个任务分配给一个组。这意味着这个组的每一个成员都是处理这个任务的**候选人(candidate)**。
-
-现在可以将前面这些东西整合起来,构造一个简单的Java程序。创建一个新的Eclipse项目,在它的classpath中添加Flowable JAR与依赖(可以在Flowable发行版的__libs__目录下找到)。在调用Flowable服务前,需要首先构建++ProcessEngine++,用于访问服务。这里我们使用__'独立(standalone)'__配置,这个配置会构建++ProcessEngine++,并使用与演示配置中相同的数据库。
-
-可以从link:$$images/FinancialReportProcess.bpmn20.xml$$[这里]下载流程定义XML。这个文件包含了上面展示的XML,同时包含了必要的BPMN<>,用于在Flowable的工具中可视化地展示流程。
-
-[source,java,linenums]
-----
-public static void main(String[] args) {
-
- // 创建Flowable流程引擎
- ProcessEngine processEngine = ProcessEngineConfiguration
- .createStandaloneProcessEngineConfiguration()
- .buildProcessEngine();
-
- // 获取Flowable服务
- RepositoryService repositoryService = processEngine.getRepositoryService();
- RuntimeService runtimeService = processEngine.getRuntimeService();
-
- // 部署流程定义
- repositoryService.createDeployment()
- .addClasspathResource("FinancialReportProcess.bpmn20.xml")
- .deploy();
-
- // 启动流程实例
- runtimeService.startProcessInstanceByKey("financialReport");
-}
-----
-
-
-[[bpmnFirstExampleCandidateList]]
-
-==== 任务列表
-
-现在可以通过如下代码获取这个任务:
-
-[source,java,linenums]
-----
-List tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();
-----
-
-请注意传递给这个操作的用户需要是__accountancy__组的成员,因为在流程定义中是这么声明的:
-
-[source,xml,linenums]
-----
-
-
- accountancy
-
-
-----
-
-也可以使用任务查询API,用组名查得相同结果。可以在代码中添加下列逻辑:
-
-[source,java,linenums]
-----
-TaskService taskService = processEngine.getTaskService();
-List tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
-----
-
-因为我们使用与演示配置中相同的数据库配置++ProcessEngine++,因此可以直接登录link:$$http://localhost:8080/flowable-idm/$$[Flowable IDM]。使用admin/test登录,创建两个新用户__kermit__与__fozzie__,并将__Access the workflow application(访问工作流应用)__权限授予他们。然后创建两个组,命名为__accountancy__与__management__,并将fozzie添加至accountancy组,将kermit添加至management组。
-然后以fozzie登录link:$$http://localhost:8080/flowable-task/$$[Flowable task]应用。选择Task应用,再选择其__Processes__页面,选择__'Monthly financial report (月度财务报告)'__,这样就可以启动我们的业务流程。
-
-
-image::images/bpmn.financial.report.example.start.process.png[align="center"]
-
-前面已经解释过,流程会执行直到第一个用户任务。因为登录为fozzie,所以可以看到在启动流程实例后,他有一个新的候选任务(candidate task)。选择__Task__页面来查看这个新任务。请注意即使流程是由其他人启动的,accountancy组中的每一个人仍然都能看到这个候选任务。
-
-
-image::images/bpmn.financial.report.example.task.assigned.png[align="center"]
-
-[[bpmnFirstExampleClaimTask]]
-
-
-==== 申领任务
-
-会计师(accountancy组的成员)现在需要**申领任务(claim)**。申领任务后,这个用户会成为任务的**执行人(assignee)**,这个任务也会从accountancy组的其他成员的任务列表中消失。可以通过如下代码实现申领任务:
-
-
-[source,java,linenums]
-----
-taskService.claim(task.getId(), "fozzie");
-----
-
-这个任务现在在**申领任务者的个人任务列表中**。
-
-[source,java,linenums]
-----
-List tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
-----
-
-在Flowable Task应用中,点击__claim__按钮会执行相同操作。这个任务会转移到登录用户的个人任务列表中。也可以看到任务执行人变更为当前登录用户。
-
-image::images/bpmn.financial.report.example.claim.task.png[align="center"]
-
-
-
-[[bpmnFirstExampleCompleteTask]]
-
-
-==== 完成任务
-
-会计师(accountancy组的成员)现在需要开始撰写财务报告了。完成报告后,他就可以**完成任务(complete)**,代表任务的所有工作都已完成。
-
-[source,java,linenums]
-----
-taskService.complete(task.getId());
-----
-
-对于Flowable引擎来说,这是个外部信号,指示流程实例可以继续执行。Flowable会从运行时数据中移除任务,并沿着这个任务唯一的出口转移线(outgoing transition),将执行移至第二个任务(__'verification of the report 审核报告'__)。为第二个任务分配执行人的机制,与上面介绍的第一个任务使用的机制相同。唯一的区别是这个任务会分配给__management__组。
-
-在演示设置中,完成任务可以通过点击任务列表中的__complete__按钮。因为Fozzie不是经理,我们需要登出Flowable Task应用,并用__kermit__(他是经理)登录。这样就可以在未分配任务列表中看到第二个任务。
-
-
-[[bpmnFirstExampleEndingProcess]]
-
-
-==== 结束流程
-
-可以使用与之前完全相同的方式获取并申领审核任务。完成这个第二个任务会将流程执行移至结束事件,并结束流程实例。这个流程实例,及所有相关的运行时执行数据都会从数据库中移除。
-
-也可以通过编程方式,使用++historyService++验证流程已经结束
-
-[source,java,linenums]
-----
-HistoryService historyService = processEngine.getHistoryService();
-HistoricProcessInstance historicProcessInstance =
-historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
-System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
-----
-
-[[bpmnFirstExampleCode]]
-
-
-==== 代码总结
-
-将之前章节的所有代码片段整合起来,会得到类似这样的代码。这段代码考虑到了你可能已经使用Flowable UI应用启动了一些流程实例。代码中总是获取任务列表而不是一个任务,因此可以正确执行:
-
-[source,java,linenums]
-----
-public class TenMinuteTutorial {
-
- public static void main(String[] args) {
-
- // 创建Flowable流程引擎
- ProcessEngine processEngine = ProcessEngineConfiguration
- .createStandaloneProcessEngineConfiguration()
- .buildProcessEngine();
-
- // 获取Flowable服务
- RepositoryService repositoryService = processEngine.getRepositoryService();
- RuntimeService runtimeService = processEngine.getRuntimeService();
-
- // 部署流程定义
- repositoryService.createDeployment()
- .addClasspathResource("FinancialReportProcess.bpmn20.xml")
- .deploy();
-
- // 启动流程实例
- String procId = runtimeService.startProcessInstanceByKey("financialReport").getId();
-
- // 获取第一个任务
- TaskService taskService = processEngine.getTaskService();
- List tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
- for (Task task : tasks) {
- System.out.println("Following task is available for accountancy group: " + task.getName());
-
- // 申领任务
- taskService.claim(task.getId(), "fozzie");
- }
-
- // 验证Fozzie获取了任务
- tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
- for (Task task : tasks) {
- System.out.println("Task for fozzie: " + task.getName());
-
- // 完成任务
- taskService.complete(task.getId());
- }
-
- System.out.println("Number of tasks for fozzie: "
- + taskService.createTaskQuery().taskAssignee("fozzie").count());
-
- // 获取并申领第二个任务
- tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
- for (Task task : tasks) {
- System.out.println("Following task is available for management group: " + task.getName());
- taskService.claim(task.getId(), "kermit");
- }
-
- // 完成第二个任务并结束流程
- for (Task task : tasks) {
- taskService.complete(task.getId());
- }
-
- // 验证流程已经结束
- HistoryService historyService = processEngine.getHistoryService();
- HistoricProcessInstance historicProcessInstance =
- historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
- System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
- }
-
-}
-----
-
-
-[[bpmnFirstExampleFutureEnhancements]]
-
-
-==== 后续增强
-
-可以看出这个业务流程太简单了,不能实际使用。但只要继续学习Flowable中可用的BPMN 2.0结构,就可以通过以下元素增强业务流程:
-
-* 定义**网关(gateway)**使经理可以选择:驳回财务报告,并重新为会计师创建任务;或者接受报告。
-* 定义并使用**变量(variables)**存储或引用报告,并可以在表单中显示它。
-* 在流程结束处定义**服务任务(service task)**,将报告发送给每一个投资人。
-* 等等。
diff --git a/docs/userguide/src/zh_CN/bpmn/ch07b-BPMN-Constructs.adoc b/docs/userguide/src/zh_CN/bpmn/ch07b-BPMN-Constructs.adoc
deleted file mode 100755
index bb447f23ee9..00000000000
--- a/docs/userguide/src/zh_CN/bpmn/ch07b-BPMN-Constructs.adoc
+++ /dev/null
@@ -1,5292 +0,0 @@
-[[bpmnConstructs]]
-
-== BPMN 2.0结构
-
-本章节介绍Flowable支持的BPMN 2.0结构,以及Flowable对BPMN标准的自定义扩展。
-
-
-[[bpmnCustomExtensions]]
-
-
-=== 自定义扩展
-
-BPMN 2.0标准对流程的所有的参与者都很有用。最终用户不会因为依赖专有解决方案,而被供应商“绑架”。Flowable之类的开源框架,也可以提供与大型供应商的解决方案相同(经常是更好;-)的实现。有了BPMN 2.0标准,从大型供应商解决方案向Flowable的迁移,可以十分简单平滑。
-
-缺点则是标准通常是不同公司(不同观点)大量讨论与妥协的结果。作为阅读BPMN 2.0 XML流程定义的开发者,有时会觉得某些结构或方法十分笨重。Flowable将开发者的感受放在最高优先,因此引入了一些**'Flowable BPMN扩展(extensions)'**。这些“扩展”并不在BPMN 2.0规格中,有些是新结构,有些是对特定结构的简化。
-
-尽管BPMN 2.0规格明确指出可以支持自定义扩展,我们仍做了如下保证:
-
-* 自定义扩展**保证是**在**标准方式**的基础上进行简化。因此当你决定使用自定义扩展时,不用担心无路可退(仍然可以用标准方式)。
-* 使用自定义扩展时,总是通过**flowable:**命名空间前缀,明确标识出XML元素、属性等。请注意Flowable引擎也支持**activiti:**命名空间前缀。
-
-因此是否使用自定义扩展,完全取决于你自己。有些其他因素会影响选择(图形化编辑器的使用,公司策略,等等)。我们提供扩展,只是因为相信标准中的某些地方可以用更简单或效率更高的方式处理。请不要吝啬给我们反馈你对扩展的评价(正面的或负面的),也可以给我们提供关于自定义扩展的新想法。说不定某一天,你的想法会成为标准的一部分!
-
-
-[[bpmnEvents]]
-
-=== 事件
-
-事件(event)通常用于为流程生命周期中发生的事情建模。事件总是图形化为圆圈。在BPMN 2.0中,有两种主要的事件分类:__捕获(catching)__与__抛出(throwing)__事件。
-
-* **捕获:** 当流程执行到达这个事件时,会等待直到触发器动作。触发器的类型由其中的图标,或者说XML中的类型声明而定义。捕获事件与抛出事件显示上的区别,是其内部的图标没有填充(即是白色的)。
-* **抛出:** 当流程执行到达这个事件时,会触发一个触发器。触发器的类型,由其中的图标,或者说XML中的类型声明而定义。抛出事件与捕获事件显示上的区别,是其内部的图标填充为黑色。
-
-[[eventDefinitions]]
-
-
-==== 事件定义
-
-事件定义(event definition),用于定义事件的语义。没有事件定义的话,事件就“不做什么特别的事情”。例如,一个没有事件定义的开始事件,并不限定具体是什么启动了流程。如果为这个开始事件添加事件定义(例如定时器事件定义),就声明了启动流程的“类型”(例如对于定时器事件定义,就是到达了特定的时间点)。
-
-
-[[timerEventDefinitions]]
-
-
-==== 定时器事件定义
-
-定时器事件(timer event definition),是由定时器所触发的事件。可以用于<>,<>,或<>。定时器事件的行为取决于所使用的业务日历(business calendar)。定时器事件有默认的业务日历,但也可以为每个定时器事件定义,单独定义业务日历。
-
-
-[source,xml,linenums]
-----
-
- ...
-
-----
-
-其中businessCalendarName指向流程引擎配置中的业务日历。如果省略业务日历定义,则使用默认业务日历。
-
-定时器定义必须且只能包含下列的一种元素:
-
-* **timeDate**。这个元素指定了link:$$http://en.wikipedia.org/wiki/ISO_8601#Dates$$[ISO 8601]格式的固定时间。在这个时间就会触发触发器。例如:
-
-[source,xml,linenums]
-----
-
- 2011-03-11T12:13:14
-
-----
-
-* **timeDuration**。要定义定时器需要等待多长时间再触发,可以用__timerEventDefinition__的子元素__timeDuration__。使用link:$$http://en.wikipedia.org/wiki/ISO_8601#Durations$$[ISO 8601]格式(BPMN 2.0规范要求)。例如(等待10天):
-
-[source,xml,linenums]
-----
-
- P10D
-
-----
-
-* **timeCycle**。指定重复周期,可用于周期性启动流程,或者为超期用户任务多次发送提醒。这个元素可以使用两种格式。第一种是按照link:$$http://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals$$[ISO 8601]标准定义的循环时间周期。例如(三次重复间隔,每次间隔为10小时):
-
-* 也可以使用__timeCycle__的可选属性__endDate__,或者像这样直接写在时间表达式的结尾:++R3/PT10H/${EndDate}++。
-当到达endDate时,应用会停止,并为该任务创建其他作业。
-可以使用link:$$http://en.wikipedia.org/wiki/ISO_8601#Dates$$[ISO 8601]标准的常量,如__"2015-02-25T16:42:11+00:00"__。也可以使用变量,如__${EndDate}__
-
-
-[source,xml,linenums]
-----
-
- R3/PT10H
-
-----
-
-[source,xml,linenums]
-----
-
- R3/PT10H/${EndDate}
-
-----
-
-如果同时使用了两种格式,则系统会使用以属性方式定义的endDate。
-
-目前只有__BoundaryTimerEvents__与__CatchTimerEvent__可以使用__EndDate__。
-
-另外,也可以使用cron表达式指定定时周期。下面的例子展示了一个整点启动,每5分钟触发的触发器:
-
-
-----
-0 0/5 * * * ?
-----
-
-
-请参考link:$$http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html$$[这个教程]了解如何使用cron表达式。
-
-**请注意:** 与普通的Unix cron不同,第一个符号代表的是秒,而不是分钟。
-
-重复时间周期更适合使用相对时间,也就是从某个特定时间点开始计算(比如用户任务开始的时间)。而cron表达式可以使用绝对时间,因此更适合用于<>。
-
-可以在定时事件定义中使用表达式,也就是使用流程变量控制定时。这个流程变量必须是包含合适时间格式的字符串,ISO 8601(或者对于循环类型,cron)。
-
-[source,xml,linenums]
-----
-
-
- ${duration}
-
-
-----
-
-**请注意:**定时器只有在异步执行器启用时才能触发(需要在++flowable.cfg.xml++中,将__asyncExecutorActivate__设置为++true++。因为默认情况下异步执行器都是禁用的)。
-
-
-
-[[bpmnErrorEventDefinition]]
-
-
-==== 错误事件定义
-
-(error event definition)
-
-**重要提示:** BPMN错误与Java异常**不**是一回事。事实上,这两者毫无共同点。BPMN错误事件是建模__业务异常(business exceptions)__的方式。而Java异常会按<>处理。
-
-[source,xml,linenums]
-----
-
-
-
-
-----
-
-[[bpmnSignalEventDefinition]]
-
-
-==== 信号事件定义
-
-信号事件(signal event),是引用具名信号的事件。信号是全局范围(广播)的事件,并会被传递给所有激活的处理器(等待中的流程实例/捕获信号事件 catching signal events)。
-
-使用++signalEventDefinition++元素声明信号事件定义。其++signalRef++属性引用一个++signal++元素,该++signal++元素需要声明为++definitions++根元素的子元素。下面摘录一个流程,使用中间事件(intermediate event)抛出与捕获信号事件。
-
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
- ...
-
-
-
-
- ...
-
-
-----
-
-两个++signalEventDefinition++引用同一个++signal++元素。
-
-
-[[bpmnSignalEventDefinitionThrow]]
-
-===== 抛出信号事件
-
-信号可以由流程实例使用BPMN结构抛出(throw),也可以通过编程方式使用Java API抛出。下面++org.flowable.engine.RuntimeService++中的方法可以用编程方式抛出信号:
-
-[source,java,linenums]
-----
-RuntimeService.signalEventReceived(String signalName);
-RuntimeService.signalEventReceived(String signalName, String executionId);
-----
-
-++signalEventReceived(String signalName)++与++signalEventReceived(String signalName, String executionId)++的区别,是前者在全局范围为所有已订阅处理器抛出信号(广播),而后者只为指定的执行传递信号。
-
-
-
-[[bpmnSignalEventDefinitionCatch]]
-
-===== 捕获信号事件
-
-可以使用信号捕获中间事件(intermediate catch signal event)或者信号边界事件(signal boundary event)捕获信号事件。
-
-
-[[bpmnSignalEventDefinitionQuery]]
-
-===== 查询信号事件订阅
-
-可以查询订阅了某一信号事件的所有执行:
-
-[source,java,linenums]
-----
- List executions = runtimeService.createExecutionQuery()
- .signalEventSubscriptionName("alert")
- .list();
-----
-
-可以使用++signalEventReceived(String signalName, String executionId)++方法为这些执行传递这个信号。
-
-
-[[bpmnSignalEventDefinitionScope]]
-
-
-===== 信号事件的范围
-
-默认情况下,信号事件在__流程引擎全局广播__。这意味着你可以在一个流程实例中抛出一个信号事件,而不同流程定义的不同流程实例都会响应这个事件。
-
-但有时也会希望只在__同一个流程实例__中响应信号事件。例如,在流程实例中使用异步机制,而两个或多个活动彼此互斥的时候。
-
-要限制信号事件的__范围(scope)__,在信号事件定义中添加(非BPMN 2.0标准!)__scope属性__:
-
-
-[source,xml,linenums]
-----
-
-----
-
-这个属性的默认值为__"global(全局)"__。
-
-
-[[bpmnSignalEventDefinitionExample]]
-
-
-===== 信号事件示例
-
-下面是一个不同流程通过信号通信的例子。第一个流程在保险政策更新或变更时启动。在变更由人工审核之后,会抛出信号事件,指出政策已经发生了变更:
-
-image::images/bpmn.signal.event.throw.png[align="center"]
-
-这个事件可以被所有感兴趣的流程实例捕获。下面是一个订阅这个事件的流程的例子。
-
-image::images/bpmn.signal.event.catch.png[align="center"]
-
-**请注意:**要理解信号事件会广播给**所有**激活的处理器,这很重要。这意味着在上面的例子中,所有订阅这个信号的流程实例都会接收这个信号。在这个例子中这就是我们期望的。然而,有的情况下,不希望使用广播方式。考虑下面的流程:
-
-
-image::images/bpmn.signal.event.warning.1.png[align="center"]
-
-
-Flowable不支持上面流程中描述的模式。我们的想法是,在执行"do something"任务时抛出的错误,由错误边界事件捕获,并通过信号抛出事件传播至执行的并行分支,最终中断"do something in parallel"任务。到目前为止Flowable会按照预期效果执行。**然而,由于信号的广播效应,它也会被传播至所有其他订阅了这个信号事件的流程实例。**这可能并非我们希望的效果。
-
-**请注意:**信号事件与特定的流程实例无关,而是会广播给所有流程实例。如果你需要只为某一特定的流程实例传递信号,则需要使用++signalEventReceived(String signalName, String executionId)++手动建立关联,并使用适当的的<>。
-
-Flowable提供了解决的方法。可以在信号事件上添加__scope__属性,并将其设置为__processInstance__。
-
-
-[[bpmnMessageEventDefinition]]
-
-
-==== 消息事件定义
-
-消息事件(message event),是指引用具名消息的事件。消息具有名字与载荷。与信号不同,消息事件只有一个接收者。
-
-消息事件定义使用++messageEventDefinition++元素声明。其++messageRef++属性引用一个++message++元素,该++message++元素需要声明为++definitions++根元素的子元素。下面摘录一个流程,声明了两个消息事件,并由开始事件与消息捕获中间事件(intermediate catching message event)引用。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
- ...
-
-
-
- ...
-
-
-
-----
-
-
-[[bpmnMessageEventDefinitionThrow]]
-
-
-===== 抛出消息事件
-
-作为嵌入式的流程引擎,Flowable并不关心实际如何接收消息。因为这可能与环境相关,或需要进行平台定义的操作。例如连接至JMS(Java Messaging Service,Java消息服务)队列(Queue)/主题(Topic),或者处理Webservice或者REST请求。因此接收消息需要作为应用的一部分,或者是流程引擎所嵌入的基础框架中的一部分,由你自行实现。
-
-在应用中接收到消息后,需要决定如何处理它。如果这个消息需要启动新的流程实例,可以选择一种由runtime服务提供的方法:
-
-
-[source,java,linenums]
-----
-ProcessInstance startProcessInstanceByMessage(String messageName);
-ProcessInstance startProcessInstanceByMessage(String messageName, Map processVariables);
-ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey,
- Map processVariables);
-----
-
-这些方法使用消息启动流程实例。
-
-如果需要由已有的流程实例接收消息,需要首先将消息与特定的流程实例关联(查看后续章节),然后触发等待中的执行,让流程继续进行。runtime服务提供了下列方法,可以触发订阅了消息事件的执行:
-
-[source,java,linenums]
-----
-void messageEventReceived(String messageName, String executionId);
-void messageEventReceived(String messageName, String executionId, HashMap processVariables);
-----
-
-
-[[bpmnMessageEventDefinitionQuery]]
-
-
-===== 查询消息事件订阅
-
-* 对于消息启动事件(message start event),消息事件的订阅与的__流程定义__相关。可以使用++ProcessDefinitionQuery++查询这种类型的消息订阅:
-
-[source,java,linenums]
-----
-ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
- .messageEventSubscription("newCallCenterBooking")
- .singleResult();
-----
-
-因为一个消息只能被一个流程定义订阅,因此这个查询总是返回0或1个结果。如果流程定义更新了,只有该流程定义的最新版本会订阅这个消息事件。
-
-* 对于消息捕获中间事件(intermediate catch message event),消息事件的订阅与__执行__相关。可以使用++ExecutionQuery++查询这种类型的消息订阅:
-
-
-[source,java,linenums]
-----
-Execution execution = runtimeService.createExecutionQuery()
- .messageEventSubscriptionName("paymentReceived")
- .variableValueEquals("orderId", message.getOrderId())
- .singleResult();
-----
-
-这种查询通常都会有关联查询,并且通常需要了解流程的情况(在这个例子里,对于给定的orderId,至多只有一个流程实例)。
-
-
-[[bpmnMessageEventDefinitionExample]]
-
-
-===== 消息事件示例
-
-下面是一个流程的例子,可以使用两种不同的消息启动:
-
-image::images/bpmn.start.message.event.example.1.png[align="center"]
-
-在流程需要通过不同的方式启动,但是后续使用统一的方式处理时,就可以使用这种方法。
-
-
-[[bpmnStartEvents]]
-
-
-==== 启动事件
-
-启动事件(start event)是流程的起点。启动事件的类型(流程在消息到达时启动,在指定的时间间隔后启动,等等),定义了流程__如何__启动,并显示为启动事件中的小图标。在XML中,类型由子元素声明来定义。
-
-启动事件**随时捕获**:启动事件(保持)等候,直到特定的触发器被触发。
-
-在启动事件中,可以使用下列Flowable自定义参数:
-
-* *initiator*: 指明保存认证用户(authenticated user)ID用的变量名。在流程启动时,操作用户的ID会保存在这个变量中。例如:
-
-[source,xml,linenums]
-----
-
-----
-
-认证用户必须在try-finally块中调用++IdentityService.setAuthenticatedUserId(String)++方法进行设置。像这样:
-
-[source,java,linenums]
-----
-try {
- identityService.setAuthenticatedUserId("bono");
- runtimeService.startProcessInstanceByKey("someProcessKey");
-} finally {
- identityService.setAuthenticatedUserId(null);
-}
-
-----
-
-这段代码已经集成在Flowable应用中,可以在<>中使用。
-
-[[bpmnNoneStartEvent]]
-
-
-==== 空启动事件
-
-[[noneStartEventDescription]]
-
-
-===== 描述
-
-“空”启动事件(none Start Event),指的是未指定启动流程实例触发器的启动事件。引擎将无法预知何时启动流程实例。空启动事件用于流程实例通过调用下列__startProcessInstanceByXXX__ API方法启动的情况。
-
-[source,java,linenums]
-----
-ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX();
-----
-
-__请注意:__子流程(sub-process)必须有空启动事件。
-
-
-[[noneStartEventGraphicalNotation]]
-
-
-===== 图示
-
-空启动事件用空心圆圈表示,中间没有图标(也就是说,没有触发器)。
-
-image::images/bpmn.none.start.event.png[align="center"]
-
-
-[[noneStartEventXml]]
-
-
-===== XML表示
-
-空启动事件的XML表示格式,就是普通的启动事件声明,而没有任何子元素(其他种类的启动事件都有用于声明其类型的子元素)。
-
-[source,xml,linenums]
-----
-
-----
-
-
-[[noneStartEventCustomExtension]]
-
-
-===== 空启动事件的自定义扩展
-
-*formKey*: 引用表单定义,用户需要在启动新流程实例时填写该表单。可以在<>找到更多信息。例如:
-
-[source,xml,linenums]
-----
-
-----
-
-
-[[bpmnTimerStartEvent]]
-
-
-==== 定时器启动事件
-
-[[timerStartEventDescription]]
-
-
-===== 描述
-
-定时器启动事件(timer start event)在指定时间创建流程实例。在流程只需要启动一次,或者流程需要在特定的时间间隔重复启动时,都可以使用。
-
-__请注意:__子流程不能有定时器启动事件。
-
-__请注意:__定时器启动事件,在流程部署的同时就开始计时。不需要调用startProcessInstanceByXXX就会在时间启动。调用startProcessInstanceByXXX时会在定时启动之外额外启动一个流程。
-
-__请注意:__当部署带有定时器启动事件的流程的更新版本时,上一版本的定时器作业会被移除。这是因为通常并不希望旧版本的流程仍然自动启动新的流程实例。
-
-
-[[timerStartEventGraphicalNotation]]
-
-
-===== 图示
-
-定时器启动事件,用其中有一个钟表图标的圆圈来表示。
-
-image::images/bpmn.clock.start.event.png[align="center"]
-
-
-[[timerStartEventXml]]
-
-
-===== XML表示
-
-定时器启动事件的XML表示格式,是普通的启动事件声明加上定时器定义子元素。请参考<>了解详细配置方法。
-
-示例:流程会启动4次,间隔5分钟,从2011年3月11日,12:13开始
-
-[source,xml,linenums]
-----
-
-
- R4/2011-03-11T12:13/PT5M
-
-
-----
-
-示例:流程会在设定的时间启动一次
-
-[source,xml,linenums]
-----
-
-
- 2011-03-11T12:13:14
-
-
-----
-
-
-[[bpmnMessageStartEvent]]
-
-
-==== 消息启动事件
-
-[[messageStartEventDescription]]
-
-
-===== 描述
-
-<>启动事件(message start event)使用具名消息启动流程实例。消息名用于__选择__正确的启动事件。
-
-当**部署**具有一个或多个消息启动事件的流程定义时,会做如下判断:
-
-* 给定流程定义中,消息启动事件的名字必须是唯一的。一个流程定义不得包含多个同名的消息启动事件。如果流程定义中有两个或多个消息启动事件引用同一个消息,或者两个或多个消息启动事件引用了具有相同消息名字的消息,则Flowable会在部署这个流程定义时抛出异常。
-* 在所有已部署的流程定义中,消息启动事件的名字必须是唯一的。如果在流程定义中,一个或多个消息启动事件引用了已经部署的另一流程定义中消息启动事件的消息名,则Flowable会在部署这个流程定义时抛出异常。
-* 流程版本:在部署流程定义的新版本时,会取消上一版本的消息订阅,即使新版本中并没有这个消息事件)。
-
-在**启动**流程实例时,可以使用下列++RuntimeService++中的方法,触发消息启动事件:
-
-[source,java,linenums]
-----
-ProcessInstance startProcessInstanceByMessage(String messageName);
-ProcessInstance startProcessInstanceByMessage(String messageName, Map processVariables);
-ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey,
- Map
-
-
-
-
-
-
-
-
- ...
-
-
-
-----
-
-
-[[bpmnSignalStartEvent]]
-
-
-==== 信号启动事件
-
-[[bpmnSignalStartEventDescription]]
-
-
-===== 描述
-
-<>启动事件(signal start event),使用具名信号启动流程实例。这个信号可以由流程实例中的信号抛出中间事件(intermediary signal throw event),或者API(__runtimeService.signalEventReceivedXXX__方法)触发。两种方式都会启动所有拥有相同名字信号启动事件的流程定义。
-
-请注意可以选择异步还是同步启动流程实例。
-
-需要为API传递的++signalName++,是由++signal++元素的++name++属性决定的名字。++signal++元素由++signalEventDefinition++的++signalRef++属性引用。
-
-[[signalStartEventGraphicalNotation]]
-
-
-===== 图示
-
-信号启动事件用其中有一个信号事件标志的圆圈表示。这个标志并未填充,用以表示捕获(接收)行为。
-
-image::images/bpmn.start.signal.event.png[align="center"]
-
-
-[[signalStartEventXml]]
-
-
-===== XML表示
-
-信号启动事件的XML表示格式,为普通启动事件声明,加上signalEventDefinition子元素:
-
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-----
-
-[[bpmnErrorStartEvent]]
-
-
-==== 错误启动事件
-
-[[errorStartEventDescription]]
-
-
-===== 描述
-
-<>启动事件(error start event),可用于触发事件子流程(Event Sub-Process)。**错误启动事件不能用于启动流程实例**。
-
-错误启动事件总是中断。
-
-[[errorStartEventGraphicalNotation]]
-
-
-===== 图示
-
-错误启动事件用其中有一个错误事件标志的圆圈表示。这个标志并未填充,用以表示捕获(接收)行为。
-
-image::images/bpmn.start.error.event.png[align="center"]
-
-
-[[errorStartEventXml]]
-
-
-===== XML表示
-
-错误启动事件的XML表示格式,为普通启动事件声明加上errorEventDefinition子元素:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnEndEvent]]
-
-
-==== 结束事件
-
-结束事件(end event)标志着流程或子流程中一个分支的结束。结束事件**总是抛出(型)事件**。这意味着当流程执行到达结束事件时,会抛出一个__结果__。结果的类型由事件内部的黑色图标表示。在XML表示中,类型由子元素声明给出。
-
-
-[[bpmnNoneEndEvent]]
-
-
-==== 空结束事件
-
-[[noneEndEventDescription]]
-
-
-===== 描述
-
-“空”结束事件(none end event),意味着当到达这个事件时,没有特别指定抛出的__结果__。因此,引擎除了结束当前执行分支之外,不会多做任何事情。
-
-[[bpmnNoneEndEventDescription]]
-
-
-===== 图示
-
-空结束事件,用其中没有图标(没有结果类型)的粗圆圈表示。
-
-image::images/bpmn.none.end.event.png[align="center"]
-
-
-[[bpmnNoneStartEventXml]]
-
-
-===== XML表示
-
-空事件的XML表示格式为普通结束事件声明,没有任何子元素(其它种类的结束事件都有子元素,用于声明其类型)。
-
-
-[source,xml,linenums]
-----
-
-----
-
-
-[[bpmnErrorEndEvent]]
-
-
-==== 错误结束事件
-
-[[bpmnErrorEndEventDescription]]
-
-
-===== 描述
-
-当流程执行到达**错误结束事件(error end event)**时,结束执行的当前分支,并抛出错误。这个错误可以<>。如果找不到匹配的错误边界事件,将会抛出异常。
-
-
-[[bpmnErrorEndEventGraphicalNotation]]
-
-
-===== 图示
-
-错误结束事件事件用内部有一个错误图标的标准结束事件(粗圆圈)表示。错误图标是全黑的,代表抛出的含义。
-
-image::images/bpmn.error.end.event.png[align="center"]
-
-
-[[bpmnErrorEndEventXml]]
-
-
-===== XML表示
-
-错误结束事件表示为结束事件,加上__errorEventDefinition__子元素:
-
-[source,xml,linenums]
-----
-
-
-
-
-----
-
-__errorRef__属性可以引用在流程外定义的__error__元素:
-
-[source,xml,linenums]
-----
-
-...
-
-...
-----
-
-__error__的**errorCode**用于查找匹配的错误捕获边界事件。如果__errorRef__不匹配任何已定义的__error__,则该__errorRef__会用做__errorCode__的快捷方式。这个快捷方式是Flowable特有的。下面的代码片段在功能上是相同的。
-
-[source,xml,linenums]
-----
-
-...
-
-...
-
-
-
-...
-----
-
-与下面的代码功能相同
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-请注意__errorRef__必须遵从BPMN 2.0概要(schema),且必须是合法的QName。
-
-[[bpmnTerminateEndEvent]]
-
-==== 终止结束事件
-
-===== 描述
-
-当到达__终止结束事件(terminate end event)__时,当前的流程实例或子流程会被终止。也就是说,当执行到达终止结束事件时,会判断第一个__范围 scope__(流程或子流程)并终止它。请注意在BPMN 2.0中,子流程可以是嵌入式子流程,调用活动,事件子流程,或事务子流程。有一条通用规则:当存在多实例的调用过程或嵌入式子流程时,只会终止一个实例,其他的实例与流程实例不会受影响。
-
-可以添加一个可选属性__terminateAll__。当其为__true__时,无论该终止结束事件在流程定义中的位置,也无论它是否在子流程(甚至是嵌套子流程)中,都会终止(根)流程实例。
-
-===== 图示
-
-终止结束事件用内部有一个全黑圆的标准结束事件(粗圆圈)表示。
-
-image::images/bpmn.terminate.end.event.png[align="center"]
-
-
-===== XML表示
-
-终止结束事件,表示为结束事件,加上__terminateEventDefinition__子元素。
-
-请注意__terminateAll__属性是可选的(默认为__false__)。
-
-[source,xml,linenums]
-----
-
-
-----
-
-[[bpmnCancelEndEvent]]
-
-==== 取消结束事件
-
-[[bpmnCancelEndEventDescription]]
-
-
-===== 描述
-
-取消结束事件(cancel end event)只能与BPMN事务子流程(BPMN transaction subprocess)一起使用。当到达取消结束事件时,会抛出取消事件,且必须由取消边界事件(cancel boundary event)捕获。取消边界事件将取消事务,并触发补偿(compensation)。
-
-
-[[bpmnCancelEndEventGraphicalNotation]]
-
-
-===== 图示
-
-取消结束事件用内部有一个取消图标的标准结束事件(粗圆圈)表示。取消图标是全黑的,代表抛出的含义。
-
-image::images/bpmn.cancel.end.event.png[align="center"]
-
-
-[[bpmnCancelEndEventXml]]
-
-
-===== XML表示
-
-取消结束事件,表示为结束事件,加上__cancelEventDefinition__子元素。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnBoundaryEvent]]
-
-
-==== 边界事件
-
-边界事件(boundary event)是__捕获型__事件,依附在活动(activity)上。边界事件永远不会抛出。这意味着当活动运行时,事件将__监听__特定类型的触发器。当__捕获__到事件时,会终止活动,并沿该事件的出口顺序流继续。
-
-所有的边界事件都用相同的方式定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-边界事件由下列元素定义:
-
-* (流程范围内)唯一的标识符
-* 由**attachedToRef**属性定义的,对该事件所依附的活动的引用。请注意边界事件及其所依附的活动,应定义在相同级别(也就是说,边界事件并不包含在活动内)。
-* 定义了边界事件的类型的,形如__XXXEventDefinition__的XML子元素(例如__TimerEventDefinition__,__ErrorEventDefinition__,等等)。查阅特定的边界事件类型,以了解更多细节。
-
-
-[[bpmnTimerBoundaryEvent]]
-
-
-==== 定时器边界事件
-
-[[timerBoundaryEventDescription]]
-
-
-===== 描述
-
-定时器边界事件(timer boundary event)的行为像是跑表与闹钟。当执行到达边界事件所依附的活动时,将启动定时器。当定时器触发时(例如在特定时间间隔后),可以中断活动,并沿着边界事件的出口顺序流继续执行。
-
-
-[[bpmnTimerBoundaryEventGraphicalNotation]]
-
-
-===== 图示
-
-定时器边界事件用内部有一个定时器图标的标准边界事件(圆圈)表示。
-
-image::images/bpmn.boundary.timer.event.png[align="center"]
-
-
-[[bpmnTimerBoundaryEventXml]]
-
-
-===== XML表示
-
-定时器边界事件与<>一样定义。其中类型子元素为**timerEventDefinition**元素。
-
-[source,xml,linenums]
-----
-
-
- PT4H
-
-
-----
-
-请参考<>了解定时器配置的细节。
-
-在图示中圆圈画为虚线,如下:
-
-image::images/bpmn.non.interrupting.boundary.timer.event.png[align="center"]
-
-中断与非中断定时器事件是不同的。非中断意味着最初的活动**不会**被中断,而会保持原样。默认为中断行为。在XML表示中,__cancelActivity__属性设置为false。
-
-一个典型使用场景,是在一段时间之后发送提醒邮件,但不影响正常的流程流向。
-
-[source,xml,linenums]
-----
-
-----
-
-**请注意:**定时器边界事件只有在异步执行器(async executor)启用时才能触发(也就是说,需要在++flowable.cfg.xml++中,将__asyncExecutorActivate__设置为++true++。因为异步执行器默认情况下是禁用的。)
-
-
-[[bpmnKnownIssueBoundaryEvent]]
-
-
-===== 边界事件的已知问题
-
-所有类型的边界事件,都有一个关于并发的已知问题:不能在边界事件上附加多个出口顺序流。这个问题的解决方案,是使用一条出口顺序流,指向并行网关。
-
-image::images/bpmn.known.issue.boundary.event.png[align="center"]
-
-
-[[bpmnBoundaryErrorEvent]]
-
-
-==== 错误边界事件
-
-[[bpmnBoundaryErrorEventDescription]]
-
-
-===== 描述
-
-在活动边界上的错误__捕获__中间(事件),或简称**错误边界事件(error boundary event)**,捕获其所依附的活动范围内抛出的错误。
-
-在<>或者<>上定义错误边界事件最有意义,因为子流程的范围会包括其中的所有活动。错误可以由<>抛出。这样的错误会逐层向其上级父范围传播,直到在范围内找到一个匹配错误事件定义的错误边界事件。
-
-当捕获错误事件时,会销毁边界事件定义所在的活动,同时销毁其中所有的当前执行(例如,并行活动,嵌套子流程,等等)。流程执行将沿着边界事件的出口顺序流继续。
-
-[[bpmnBoundaryErrorEventgraphicalNotation]]
-
-
-===== 图示
-
-错误边界事件用内部有一个错误图标的标准中间事件(两层圆圈)表示。错误图标是白色的,代表__捕获__的含义。
-
-image::images/bpmn.boundary.error.event.png[align="center"]
-
-[[bpmnBoundaryErrorEventXml]]
-
-
-===== XML表示
-
-错误边界事件与标准<>一样定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-在<>中,__errorRef__引用一个流程元素外定义的错误:
-
-[source,xml,linenums]
-----
-
-...
-
-...
-
-----
-
-**errorCode**用于匹配捕获的错误:
-
-* 如果省略了__errorRef__,错误边界事件会捕获**所有错误事件**,无论__error__的errorCode是什么。
-* 如果提供了__errorRef__,并且其引用了存在的__error__,则边界事件**只会捕获相同错误代码的错误**。
-* 如果提供了__errorRef__,但BPMN 2.0文件中没有定义__error__,则**errorRef会用作errorCode**(与错误结束事件类似)。
-
-
-[[bpmnBoundaryErrorEventExample]]
-
-
-===== 示例
-
-下面的示例流程展示了如何使用错误结束事件。当__'Review profitability (审核盈利能力)'__用户任务完成,并指出提供的信息不足时,会抛出错误。当这个错误被子流程边界捕获时,__'Review sales lead (审核销售线索)'__子流程中的所有运行中活动都会被销毁(即使__'Review customer rating 审核客户等级'__还没有完成),并会创建__'Provide additional details (提供更多信息)'__用户任务。
-
-image::images/bpmn.boundary.error.example.png[align="center"]
-
-这个流程作为演示配置的示例提供。可以在__org.flowable.examples.bpmn.event.error__包中找到流程XML与单元测试。
-
-
-[[bpmnBoundarySignalEvent]]
-
-
-==== 信号边界事件
-
-[[bpmnBoundarySignalEventDescription]]
-
-
-===== 描述
-
-依附在活动边界上的<>捕获中间(事件),或简称**信号边界事件(signal boundary event)**,捕获与其信号定义具有相同名称的信号。
-
-**请注意:**与其他事件例如错误边界事件不同的是,信号边界事件不只是捕获其所依附范围抛出的信号。信号边界事件为全局范围(广播)的,意味着信号可以从任何地方抛出,甚至可以是不同的流程实例。
-
-**请注意:**与其他事件(如错误事件)不同,信号在被捕获后不会被消耗。如果有两个激活的信号边界事件,捕获相同的信号事件,则两个边界事件都会被触发,哪怕它们不在同一个流程实例里。
-
-
-[[bpmnBoundarySignalEventGraphicalNotation]]
-
-
-===== 图示
-
-信号边界事件,用内部有一个信号图标的标准中间事件(两层圆圈)表示。信号图标是白色的,代表__捕获__的含义。
-
-image::images/bpmn.boundary.signal.event.png[align="center"]
-
-
-[[bpmnBoundarySignalEventXml]]
-
-
-===== XML表示
-
-信号边界事件与标准<>一样定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnBoundarySignalEventExample]]
-
-
-===== 示例
-
-参见<>章节。
-
-
-[[bpmnBoundaryMessageEvent]]
-
-
-==== 消息边界事件
-
-[[bpmnBoundaryMessageEventDescription]]
-
-
-===== 描述
-
-在活动边界上的<>__捕获__中间(事件),或简称**消息边界事件(message boundary event)**,捕获与其消息定义具有相同消息名的消息。
-
-
-[[bpmnBoundaryMessageEventGraphicalNotation]]
-
-
-===== 图示
-
-消息边界事件,用内部有一个消息图标的标准中间事件(两层圆圈)表示。信号图标是白色的,代表__捕获__的含义。
-
-image::images/bpmn.boundary.message.event.png[align="center"]
-
-请注意消息边界事件既可以是中断型的(右图),也可以是非中断型的(左图)。
-
-
-[[bpmnBoundaryMessageEventXml]]
-
-
-===== XML表示
-
-消息边界事件与标准<>一样定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnBoundaryMessageEventExample]]
-
-
-===== 示例
-
-参见<>章节。
-
-
-[[bpmnBoundaryCancelEvent]]
-
-
-==== 取消边界事件
-
-[[bpmnBoundaryCancelEventDescription]]
-
-
-===== 描述
-
-依附在事务子流程边界上的取消__捕获__中间事件,或简称**取消边界事件(cancel boundary event)**,在事务取消时触发。当取消边界事件触发时,首先会中断当前范围的所有活动执行。接下来,启动事务范围内所有有效的的补偿边界事件(compensation boundary event)。补偿会同步执行,也就是说在离开事务前,边界事件会等待补偿完成。当补偿完成时,沿取消边界事件的任何出口顺序流离开事务子流程。
-
-
-**请注意:**一个事务子流程只允许使用一个取消边界事件。
-
-**请注意:**如果事务子流程中有嵌套的子流程,只会对成功完成的子流程触发补偿。
-
-**请注意:**如果取消边界事件放置在具有多实例特性的事务子流程上,如果一个实例触发了取消,则边界事件将取消所有实例。
-
-
-[[bpmnBoundaryCancelEventGraphicalNotation]]
-
-
-===== 图示
-
-取消边界事件,用内部有一个取消图标的标准中间事件(两层圆圈)表示。取消图标是白色的(未填充),代表__捕获__的含义。
-
-image::images/bpmn.boundary.cancel.event.png[align="center"]
-
-
-[[bpmnBoundaryCancelEventXml]]
-
-
-===== XML表示
-
-取消边界事件与标准<>一样定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-因为取消边界事件总是中断型的,因此没有++cancelActivity++属性。
-
-
-[[bpmnBoundaryCompensationEvent]]
-
-
-==== 补偿边界事件
-
-[[bpmnBoundaryCompensationEventDescription]]
-
-
-===== 描述
-
-依附在活动边界上的补偿__捕获__中间(事件),或简称**补偿边界事件(compensation boundary event)**,可以为活动附加补偿处理器。
-
-补偿边界事件必须使用直接关联的方式引用单个的补偿处理器。
-
-补偿边界事件与其它边界事件的活动策略不同。其它边界事件,例如信号边界事件,在其依附的活动启动时激活;当该活动结束时会被解除,并取消相应的事件订阅。而补偿边界事件不是这样。补偿边界事件在其依附的活动**成功完成**时激活,同时创建补偿事件的相应订阅。当补偿事件被触发,或者相应的流程实例结束时,才会移除订阅。请考虑下列因素:
-
-* 当补偿被触发时,会调用补偿边界事件关联的补偿处理器。调用次数与其依附的活动成功完成的次数相同。
-* 如果补偿边界事件依附在具有多实例特性的活动上,则会为每一个实例创建补偿事件订阅。
-* 如果补偿边界事件依附在位于循环内部的活动上,则每次该活动执行时,都会创建一个补偿事件订阅。
-* 如果流程实例结束,则取消补偿事件的订阅。
-
-**请注意:**嵌入式子流程不支持补偿边界事件。
-
-
-[[bpmnBoundaryCompensationEventGraphicalNotation]]
-
-
-===== 图示
-
-补偿边界事件,用内部有一个补偿图标的标准中间事件(两层圆圈)表示。补偿图标是白色的(未填充),代表__捕获__的含义。另外,补偿边界事件使用单向连接关联补偿处理器,如下图所示:
-
-image::images/bpmn.boundary.compensation.event.png[align="center"]
-
-
-[[bpmnBoundaryCompensationEventXml]]
-
-
-===== XML表示
-
-补偿边界事件与标准<>一样定义:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-----
-
-补偿边界事件在活动完成后才激活,因此不支持++cancelActivity++属性。
-
-
-[[bpmnIntermediateCatchingEvent]]
-
-
-==== 捕获中间事件
-
-所有的捕获中间事件(intermediate catching events)都使用相同方式定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-捕获中间事件由下列元素定义:
-
-* (流程范围内)唯一的标识符
-* 定义了捕获中间事件类型的,形如__XXXEventDefinition__的XML子元素(例如__TimerEventDefinition__等)。查阅特定中间捕获事件类型,以了解更多细节。
-
-
-[[bpmnTimerIntermediateEvent]]
-
-
-==== 定时器捕获中间事件
-
-[[bpmnTimerIntermediateEventDescription]]
-
-
-===== 描述
-
-定时器捕获中间事件(timer intermediate catching event)的行为像是跑表。当执行到达捕获事件时,启动定时器;当定时器触发时(例如在一段时间间隔后),沿定时器中间事件的出口顺序流继续执行。
-
-
-[[bpmnTimerIntermediateEventGraphicalNotation]]
-
-
-===== 图示
-
-定时器中间事件用内部有定时器图标的中间捕获事件表示。
-
-image::images/bpmn.intermediate.timer.event.png[align="center"]
-
-
-[[bpmnTimerIntermediateEventXml]]
-
-
-===== XML表示
-
-定时器中间事件与<>一样定义。子元素为**timerEventDefinition**。
-
-[source,xml,linenums]
-----
-
-
- PT5M
-
-
-----
-
-查看<>了解详细配置。
-
-
-[[bpmnIntermediateSignalEvent]]
-
-
-==== 信号捕获中间事件
-
-[[bpmnIntermediateSignalEventDescription]]
-
-
-===== 描述
-
-<>__捕获__中间事件(signal intermediate catching event),捕获与其引用的信号定义具有相同信号名称的信号。
-
-**请注意:**与其他事件如错误事件不同,信号在被捕获后不会被消耗。如果有两个激活的信号中间事件,捕获相同的信号事件,则两个中间事件都会被触发,哪怕它们不在同一个流程实例里。
-
-
-[[bpmnIntermediateSignalEventGraphicalNotation]]
-
-
-===== 图示
-
-信号捕获中间事件用内部有信号图标的标准中间事件(两层圆圈)表示。信号图标是白色的(未填充),代表__捕获__的含义。
-
-image::images/bpmn.intermediate.signal.catch.event.png[align="center"]
-
-
-[[bpmnIntermediateSignalEventXml]]
-
-
-===== XML表示
-
-信号中间事件与<>一样定义。子元素为**signalEventDefinition**。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnIntermediateSignalEventExample]]
-
-
-===== 示例
-
-参阅<>章节。
-
-[[bpmnIntermediateMessageEvent]]
-
-
-==== 消息捕获中间事件
-
-[[bpmnIntermediateMessageEventDescription]]
-
-
-===== 描述
-
-<>__捕获__中间事件(message intermediate catching event),捕获特定名字的消息。
-
-
-[[bpmnIntermediateMessageEventGraphicalNotation]]
-
-
-===== 图示
-
-消息捕获中间事件用内部有消息图标的标准中间事件(两层圆圈)表示。消息图标是白色的(未填充),代表__捕获__的含义。
-
-image::images/bpmn.intermediate.message.catch.event.png[align="center"]
-
-
-[[bpmnIntermediateMessageEventXml]]
-
-
-===== XML表示
-
-消息中间事件与<>一样定义。子元素为**messageEventDefinition**。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnIntermediateMessageEventExample]]
-
-
-===== 示例
-
-参阅<>章节。
-
-
-[[bpmnIntermediateThrowEvent]]
-
-
-==== 抛出中间事件
-
-所有的抛出中间事件(intermediate throwing evnet)都使用相同方式定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-抛出中间事件由下列元素定义:
-
-* (流程范围内)唯一的标识符
-* 定义了抛出中间事件类型的,形如__XXXEventDefinition__的XML子元素(例如__signalEventDefinition__等)。查阅特定中间抛出事件类型,以了解更多细节。
-
-[[bpmnIntermediateThrowNoneEvent]]
-
-
-==== 空抛出中间事件
-
-下面的流程图展示了空抛出中间事件(intermediate throwing none event)的简单例子。其用于指示流程已经到达了某种状态。
-
-image::images/bpmn.intermediate.none.event.png[align="center"]
-
-添加一个<>后,空中间事件就可以成为很好的监视某些KPI(Key Performance Indicators 关键绩效指标)的钩子。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-----
-
-你也可以添加一些自己的代码,将部分事件发送给你的BAM(Business Activity Monitoring 业务活动监控)工具,或者DWH(Data Warehouse 数据仓库)。在这种情况下,引擎本身不会做任何事情,只是从中穿过。
-
-
-[[bpmnIntermediateThrowSignalEvent]]
-
-
-==== 信号抛出中间事件
-
-[[bpmnIntermediateThrowSignalEventDescription]]
-
-
-===== 描述
-
-<>__抛出__中间事件(signal intermediate throwing event),抛出所定义信号的信号事件。
-
-在Flowable中,信号会广播至所有的激活的处理器(也就是说,所有的信号捕获事件)。可以同步或异步地发布信号。
-
-* 在默认配置中,信号**同步**地传递。这意味着抛出信号的流程实例会等待,直到信号传递至所有的捕获信号的流程实例。所有的捕获流程实例也会在与抛出流程实例相同的事务中,也就是说如果收到通知的流程实例中,有一个实例产生了技术错误(抛出异常),则所有相关的实例都会失败。
-* 信号也可以**异步**地传递。这是由到达抛出信号事件时的发送处理器来决定的。对于每个激活的处理器,JobExecutor会为其存储并传递一个异步通知消息(asynchronous notification message),即作业(Job)。
-
-[[bpmnIntermediateThrowSignalEventGraphicalNotation]]
-
-
-===== 图示
-
-消息抛出中间事件用内部有信号图标的标准中间事件(两层圆圈)表示。信号图标是黑色的(已填充),代表__抛出__的含义。
-
-image::images/bpmn.intermediate.signal.throw.event.png[align="center"]
-
-
-[[bpmnIntermediateThrowSignalEventXml]]
-
-
-===== XML表示
-
-信号中间事件与<>一样定义。子元素为**signalEventDefinition**。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-异步信号事件这样定义:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnIntermediateThrowSignalEventExample]]
-
-
-===== 示例
-
-参阅<>章节。
-
-
-[[bpmnIntermediateThrowCompensationEvent]]
-
-
-==== 补偿抛出中间事件
-
-[[bpmnIntermediateThrowCompensationEventDescription]]
-
-
-===== 描述
-
-补偿__抛出__中间事件(compensation intermediate throwing event)用于触发补偿。
-
-**触发补偿:**既可以为设计的活动触发补偿,也可以为补偿事件所在的范围触发补偿。补偿由活动所关联的补偿处理器执行。
-
-* 活动抛出补偿时,活动关联的补偿处理器将执行的次数,为活动成功完成的次数。
-* 抛出补偿时,当前范围中所有的活动,包括并行分支上的活动都会被补偿。
-* 补偿分层触发:如果将要被补偿的活动是一个子流程,则该子流程中所有的活动都会触发补偿。如果该子流程有嵌套的活动,则会递归地抛出补偿。然而,补偿不会传播至流程的**上层**:如果子流程中触发了补偿,该补偿不会传播至子流程范围外的活动。BPMN规范指出,对“与子流程在相同级别”的活动触发补偿。
-* 在Flowable中,补偿按照执行的相反顺序运行。这意味着最后完成的活动会第一个补偿。
-* 可以使用补偿抛出中间事件补偿已经成功完成的事务子流程。
-
-**请注意:**如果抛出补偿的范围中有一个子流程,而该子流程包含有关联了补偿处理器的活动,则当抛出补偿时,只有该子流程成功完成时,补偿才会传播至该子流程。如果子流程内嵌套的部分活动已经完成,并附加了补偿处理器,但包含这些活动的子流程还没有完成,则这些补偿处理器仍不会执行。参考下面的例子:
-
-image::images/bpmn.throw.compensation.example1.png[align="center"]
-
-在这个流程中,有两个并行的执行:一个执行嵌入子流程,另一个执行“charge credit card(信用卡付款)”活动。假定两个执行都已开始,且第一个执行正等待用户完成“review bookings(检查预定)”任务。第二个执行进行了“charge credit card(信用卡付款)”活动的操作,抛出了错误,导致“cancel reservations(取消预订)”事件触发补偿。这时并行子流程还未完成,意味着补偿不会传播至该子流程,因此不会执行“cancel hotel reservation(取消酒店预订)”补偿处理器。而如果“cancel reservations(取消预订)”运行前,这个用户任务(因此该嵌入式子流程也)已经完成,则补偿会传播至该嵌入式子流程。
-
-**流程变量:**当补偿嵌入式子流程时,用于执行补偿处理器的执行,可以访问子流程的局部流程变量在子流程完成时的值。为此,会对范围执行(为执行子流程所创建的执行)所关联的流程变量进行快照。意味着:
-
-* 补偿执行器无法访问子流程范围内并行执行所添加的变量。
-* 上层执行所关联的流程变量(例如流程实例关联的流程变量)不在该快照中。因为补偿处理器可以直接访问这些流程变量在抛出补偿时的值。
-* 只会为嵌入式子流程进行变量快照。其他活动不会进行变量快照。
-
-**目前的限制:**
-
-* 目前不支持++waitForCompletion="false"++。当补偿抛出中间事件触发补偿时,只有在补偿成功完成时,才会离开该事件。
-* 补偿由并行执行运行。并行执行会按照补偿活动完成的逆序启动。
-* 补偿不会传播至调用活动(call activity)生成的子流程。
-
-
-[[bpmnIntermediateThrowCompensationEventGraphicalNotation]]
-
-
-===== 图示
-
-补偿抛出中间事件用内部有补偿图标的标准中间事件(两层圆圈)表示。补偿图标是黑色的(已填充),代表__抛出__的含义。
-
-image::images/bpmn.intermediate.compensation.throw.event.png[align="center"]
-
-
-[[bpmnIntermediateThrowCompensationEventXml]]
-
-
-===== XML表示
-
-补偿中间事件与<>一样定义。子元素为**compensateEventDefinition**。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-另外,++activityRef++可选项用于为指定的范围或活动触发补偿:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-
-[[bpmnSequenceFlow]]
-
-
-=== 顺序流
-
-[[sequenceFlowDescription]]
-
-
-==== 描述
-
-顺序流(sequence flow)是流程中两个元素间的连接器。在流程执行过程中,一个元素被访问后,会沿着其所有出口顺序流继续执行。这意味着BPMN 2.0的默认是并行执行的:两个出口顺序流就会创建两个独立的、并行的执行路径。
-
-[[sequenceFlowGraphicalNotation]]
-
-
-==== 图示
-
-顺序流,用从源元素指向目标元素的箭头表示。箭头总是指向目标元素。
-
-image::images/bpmn.sequence.flow.png[align="center"]
-
-
-[[sequenceFlowXml]]
-
-
-==== XML表示
-
-顺序流需要有流程唯一的**id**,并引用存在的**源**与**目标**元素。
-
-[source,xml,linenums]
-----
-
-----
-
-
-[[bpmnConditionalSequenceFlow]]
-
-
-==== 条件顺序流
-
-[[condSeqFlowDescription]]
-
-
-===== 描述
-
-在顺序流上可以定义条件(conditional sequence flow)。当离开BPMN 2.0活动时,默认行为是计算其每个出口顺序流上的条件。当条件计算为__true__时,选择该出口顺序流。如果该方法选择了多条顺序流,则会生成多个__执行__,流程会以并行方式继续。
-
-**请注意:**上面的介绍针对BPMN 2.0活动(与事件),但不适用于网关(gateway)。不同类型的网关,会用不同的方式处理带有条件的顺序流。
-
-
-[[conditionalSequenceFlowGraphicalNotation]]
-
-
-===== 图示
-
-条件顺序流用起点带有小菱形的顺序流表示。在顺序流旁显示条件表达式。
-
-image::images/bpmn.conditional.sequence.flow.png[align="center"]
-
-
-[[conditionalSequenceFlowXml]]
-
-
-===== XML表示
-
-条件顺序流的XML表示格式为含有**conditionExpression(条件表达式)**子元素的普通顺序流。请注意目前只支持__tFormalExpressions__。可以省略__xsi:type=""__定义,默认为唯一支持的表达式类型。
-
-
-[source,xml,linenums]
-----
-
-
- 100 && order.price < 250}]]>
-
-
-----
-
-目前conditionalExpressions**只能使用UEL**。详细信息可以在<>章节找到。使用的表达式需要能解析为boolean值,否则当计算条件时会抛出异常。
-
-* 下面的例子,通过典型的JavaBean的方式,使用getter引用流程变量的数据。
-
-[source,xml,linenums]
-----
-
- 100 && order.price < 250}]]>
-
-----
-
-* 这个例子调用了一个解析为boolean值的方法。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-Flowable发行版中包含了下列示例流程,用于展示值表达式与方法表达式的使用(参见__org.flowable.examples.bpmn.expression__)。
-
-image::images/bpmn.uel-expression.on.seq.flow.png[align="center"]
-
-
-[[bpmnDefaultSequenceFlow]]
-
-
-==== 默认顺序流
-
-[[bpmnDefaultSequenceFlowDescription]]
-
-
-===== 描述
-
-所有的BPMN 2.0任务与网关都可以使用**默认顺序流(default sequence flow)**。只有当没有其他顺序流可以选择时,才会选择默认顺序流作为活动的出口顺序流。流程会忽略默认顺序流上的条件。
-
-
-[[bpmnDefaultSequenceFlowGraphicalNotation]]
-
-
-===== 图示
-
-默认顺序流用起点带有“斜线”标记的一般顺序流表示。
-
-image::images/bpmn.default.sequence.flow.png[align="center"]
-
-
-[[bpmnDefaultSequenceFlowXmlRepresentation]]
-
-
-===== XML表示
-
-活动的默认顺序流由该活动的**default属性**定义。下面的XML片段展示了一个排他网关(exclusive gateway),带有默认顺序流__flow 2__。只有当__conditionA__与__conditionB__都计算为false时,才会选择默认顺序流作为网关的出口顺序流。
-
-[source,xml,linenums]
-----
-
-
-
- ${conditionA}
-
-
-
-
-
- ${conditionB}
-
-----
-
-
-对应下面的图示:
-
-image::images/bpmn.default.sequence.flow.example.png[align="center"]
-
-[[bpmnGateways]]
-
-
-=== 网关
-
-网关(gateway)用于控制执行的流向(或者按BPMN 2.0的用词:执行的__“标志(token)”__)。网关可以__消费(consuming)__与__生成(generating)__标志。
-
-网关用其中带有图标的菱形表示。该图标显示了网关的类型。
-
-image::images/bpmn.gateway.png[align="center"]
-
-
-[[bpmnExclusiveGateway]]
-
-
-==== 排他网关
-
-[[exclusiveGatewayDescription]]
-
-
-===== 描述
-
-排他网关(exclusive gateway)(也叫__异或网关 XOR gateway__,或者更专业的,__基于数据的排他网关 exclusive data-based gateway__),用于对流程中的**决策**建模。当执行到达这个网关时,会按照所有出口顺序流定义的顺序对它们进行计算。选择第一个条件计算为true的顺序流(当没有设置条件时,认为顺序流为__true__)继续流程。
-
-**请注意这里出口顺序流的含义与BPMN 2.0中的一般情况不一样。一般情况下,会选择所有条件计算为true的顺序流,并行执行。而使用排他网关时,只会选择一条顺序流。当多条顺序流的条件都计算为true时,会且仅会选择在XML中最先定义的顺序流继续流程。如果没有可选的顺序流,会抛出异常。**
-
-
-[[exclusiveGatewayGraphNotation]]
-
-
-===== 图示
-
-排他网关用内部带有'X'图标的标准网关(菱形)表示,'X'图标代表__异或__的含义。请注意内部没有图标的网关默认为排他网关。BPMN 2.0规范不允许在同一个流程中混合使用有及没有X的菱形标志。
-
-image::images/bpmn.exclusive.gateway.notation.png[align="center"]
-
-
-[[exclusiveGatewayXML]]
-
-
-===== XML表示
-
-排他网关的XML表示格式很简洁:一行定义网关的XML。条件表达式定义在其出口顺序流上。查看<>章节了解这种表达式的可用选项。
-
-以下面的模型为例:
-
-image::images/bpmn.exclusive.gateway.png[align="center"]
-
-其XML表示如下:
-
-[source,xml,linenums]
-----
-
-
-
- ${input == 1}
-
-
-
- ${input == 2}
-
-
-
- ${input == 3}
-
-----
-
-
-[[bpmnParallelGateway]]
-
-
-==== 并行网关
-
-[[bpmnParallelGatewayDescription]]
-
-
-===== 描述
-
-网关也可以建模流程中的并行执行。在流程模型中引入并行的最简单的网关,就是**并行网关(parallel gateway)**。它可以将执行__分支(fork)__为多条路径,也可以__合并(join)__多条入口路径的执行。
-
-并行网关的功能取决于其入口与出口顺序流:
-
-* **分支:**所有的出口顺序流都并行执行,为每一条顺序流创建一个并行执行。
-* **合并:**所有到达并行网关的并行执行都会在网关处等待,直到每一条入口顺序流都到达了有个执行。然后流程经过该合并网关继续。
-
-请注意,如果并行网关同时具有多条入口与出口顺序流,可以**同时具有分支与合并的行为**。在这种情况下,网关首先合并所有入口顺序流,然后分裂为多条并行执行路径。
-
-**与其他网关类型有一个重要区别:并行网关不计算条件。如果连接到并行网关的顺序流上定义了条件,会直接忽略该条件。**
-
-
-[[bpmnParallelGatewayGraphicalNotation]]
-
-
-===== 图示
-
-并行网关,用内部带有'加号'图标的网关(菱形)表示,代表__与(AND)__的含义。
-
-image::images/bpmn.parallel.gateway.png[align="center"]
-
-[[bpmnParallelGatewayXML]]
-
-
-===== XML表示
-
-定义并行网关只需要一行XML:
-
-[source,xml,linenums]
-----
-
-----
-
-
-实际行为(分支,合并或两者皆有),由连接到该并行网关的顺序流定义。
-
-例如,上面的模型表示为下面的XML:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-
-在上面的例子中,当流程启动后会创建两个任务:
-
-[source,java,linenums]
-----
-ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
-TaskQuery query = taskService.createTaskQuery()
- .processInstanceId(pi.getId())
- .orderByTaskName()
- .asc();
-
-List tasks = query.list();
-assertEquals(2, tasks.size());
-
-Task task1 = tasks.get(0);
-assertEquals("Receive Payment", task1.getName());
-Task task2 = tasks.get(1);
-assertEquals("Ship Order", task2.getName());
-----
-
-当这两个任务完成后,第二个并行网关会合并这两个执行。由于它只有一条出口顺序流,因此就不会再创建并行执行路径,而只是激活__Archive Order(存档订单)__任务。
-
-请注意并行网关不需要“平衡”(也就是说,前后对应的两个并行网关,其入口/出口顺序流的数量不需要一致)。每个并行网关都会简单地等待所有入口顺序流,并为每一条出口顺序流创建并行执行,而不受流程模型中的其他结构影响。因此,下面的流程在BPMN 2.0中是合法的:
-
-image::images/bpmn.unbalanced.parallel.gateway.png[align="center"]
-
-[[bpmnInclusiveGateway]]
-
-
-==== 包容网关
-
-[[bpmnInclusiveGatewayDescription]]
-
-
-===== 描述
-
-可以把**包容网关(inclusive gateway)**看做排他网关与并行网关的组合。与排他网关一样,可以在包容网关的出口顺序流上定义条件,包容网关会计算条件。然而主要的区别是,包容网关与并行网关一样,可以同时选择多于一条出口顺序流。
-
-包容网关的功能取决于其入口与出口顺序流:
-
-* **分支:**流程会计算所有出口顺序流的条件。对于每一条计算为true的顺序流,流程都会创建一个并行执行。
-* **合并:**所有到达包容网关的并行执行,都会在网关处等待。直到每一条具有流程标志(process token)的入口顺序流,都有一个执行到达。这是与并行网关的重要区别。换句话说,包容网关只会等待可以被执行的入口顺序流。在合并后,流程穿过合并并行网关继续。
-
-请注意,如果包容网关同时具有多条入口与出口顺序流,可以**同时具有分支与合并的行为**。在这种情况下,网关首先合并所有具有流程标志的入口顺序流,然后为每一个条件计算为true的出口顺序流分裂出并行执行路径。
-
-[quote, 译者附(翻译自alfresco文档 http://docs.alfresco.com/process-services1.6/topics/inclusive_gateway.html)]
-____
-包容网关的汇聚行为比并行网关更复杂。所有到达包容网关的并行执行,都会在网关等待,直到所有“可以到达”包容网关的执行都“到达”包容网关。
-判断方法为:计算当前流程实例中的所有执行,检查从其位置是否有一条到达包容网关的路径(忽略顺序流上的任何条件)。如果存在这样的执行(可到达但尚未到达),则不会触发包容网关的汇聚行为。
-____
-
-[[bpmnInclusiveGatewayGraphicalNotation]]
-
-
-===== 图示
-
-包容网关,用内部带有'圆圈'图标的网关(菱形)表示。
-
-image::images/bpmn.inclusive.gateway.png[align="center"]
-
-
-[[bpmnInclusiveGatewayXML]]
-
-
-===== XML表示
-
-定义包容网关需要一行XML:
-
-[source,xml,linenums]
-----
-
-----
-
-实际行为(分支,合并或两者皆有),由连接到该包容网关的顺序流定义。
-
-例如,上面的模型表现为下面的XML:
-
-[source,xml,linenums]
-----
-
-
-
-
-
- ${paymentReceived == false}
-
-
- ${shipOrder == true}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-在上面的例子中,当流程启动后,如果流程变量paymentReceived == false且shipOrder == true,会创建两个任务。如果只有一个流程变量等于true,则只会创建一个任务。如果没有条件计算为true,会抛出异常(可通过指定默出口顺序流避免)。在下面的例子中,只会创建ship order(传递订单)一个任务:
-
-[source,java,linenums]
-----
-HashMap variableMap = new HashMap();
-variableMap.put("receivedPayment", true);
-variableMap.put("shipOrder", true);
-
-ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
-
-TaskQuery query = taskService.createTaskQuery()
- .processInstanceId(pi.getId())
- .orderByTaskName()
- .asc();
-
-List tasks = query.list();
-assertEquals(1, tasks.size());
-
-Task task = tasks.get(0);
-assertEquals("Ship Order", task.getName());
-----
-
-当这个任务完成后,第二个包容网关会合并这两个执行。并且由于它只有一条出口顺序流,所有不会再创建并行执行路径,而只会激活__Archive Order(存档订单)__任务。
-
-请注意包容网关不需要“平衡”(也就是说,对应的包容网关,其入口/出口顺序流的数量不需要匹配)。包容网关会简单地等待所有入口顺序流,并为每一条出口顺序流创建并行执行,不受流程模型中的其他结构影响。
-
-请注意包容网关不需要“平衡”(也就是说,前后对应的两个包容网关,其入口/出口顺序流的数量不需要一致)。每个包容网关都会简单地等待所有入口顺序流,并为每一条出口顺序流创建并行执行,不受流程模型中的其他结构影响。
-
-[[bpmnEventbasedGateway]]
-
-
-==== 基于事件的网关
-
-[[eventBasedGatewayDescription]]
-
-
-===== 描述
-
-基于事件的网关(event-based gateway)提供了根据事件做选择的方式。网关的每一条出口顺序流都需要连接至一个捕获中间事件。当流程执行到达基于事件的网关时,与等待状态类似,网关会暂停执行,并且为每一条出口顺序流创建一个事件订阅。
-
-请注意:基于事件的网关的出口顺序流与一般的顺序流不同。这些顺序流从不实际**执行**。相反,它们用于告知流程引擎:当执行到达一个基于事件的网关时,需要订阅什么事件。有以下限制:
-
-* 一个基于事件的网关,必须有两条或更多的出口顺序流。
-* 基于事件的网关,只能连接至++intermediateCatchEvent(捕获中间事件)++类型的元素(Flowable不支持在基于事件的网关之后连接“接收任务 Receive Task”)。
-* 连接至基于事件的网关的++intermediateCatchEvent++,必须只有一个入口顺序流。
-
-
-[[eventBasedGatewayGraphNotation]]
-
-
-===== 图示
-
-基于事件的网关,用内部带有特殊图标的网关(菱形)表示。
-
-image::images/bpmn.event.based.gateway.notation.png[align="center"]
-
-
-[[eventBasedGatewayXML]]
-
-
-===== XML表示
-
-用于定义基于事件的网关的XML元素为++eventBasedGateway++。
-
-
-[[eventBasedGatewayExample]]
-
-
-===== 示例
-
-下面是一个带有基于事件的网关的示例流程。当执行到达基于事件的网关时,流程执行暂停。流程实例订阅alert信号事件,并创建一个10分钟后触发的定时器。流程引擎会等待10分钟,并同时等待信号事件。如果信号在10分钟内触发,则会取消定时器,流程沿着信号继续执行,激活Handle alert用户任务。如果10分钟内没有触发信号,则会继续执行,并取消信号订阅。
-
-image::images/bpmn.event.based.gateway.example.png[align="center"]
-
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PT10M
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-
-[[bpmnTask]]
-
-
-=== 任务
-
-[[bpmnUserTask]]
-
-
-==== 用户任务
-
-[[bpmnUserTaskDescription]]
-
-
-===== 描述
-
-“用户任务(user task)”用于对需要人工执行的任务进行建模。当流程执行到达用户任务时,会为指派至该任务的用户或组的任务列表创建一个新任务。
-
-
-[[bpmnUserTaskGraphicalNotation]]
-
-
-===== 图示
-
-用户任务用左上角有一个小用户图标的标准任务(圆角矩形)表示。
-
-image::images/bpmn.user.task.png[align="center"]
-
-
-[[bpmnUserTaskXml]]
-
-
-===== XML表示
-
-用户任务在XML中如下定义。其中__id__是必须属性,__name__是可选属性。
-
-[source,xml,linenums]
-----
-
-----
-
-也可以为用户任务添加描述(description)。事实上任何BPMN 2.0元素都可以有描述。描述由**documentation**元素定义。
-
-[source,xml,linenums]
-----
-
-
-
- Schedule an engineering meeting for next week with the new hire.
-
-----
-
-可以使用标准Java方式获取描述文本:
-
-[source,java,linenums]
-----
-task.getDescription()
-----
-
-
-[[bpmnUserTaskDueDate]]
-
-
-===== 到期日期
-
-每个任务都可以使用一个字段标志该任务的到期日期(due date)。可以使用查询API,查询在给定日期前或后到期的任务。
-
-可以在任务定义中使用扩展指定表达式,以在任务创建时设定到期日期。该表达式**必须解析为++java.util.Date++,++java.util.String (ISO8601格式)++,ISO8601时间长度(例如PT50M),或者++null++**。例如,可以使用在流程里前一个表单中输入的日期,或者由前一个服务任务计算出的日期。如果使用的是时间长度,则到期日期基于当前时间加上给定长度计算。例如当dueDate使用“PT30M”时,任务在从现在起30分钟后到期。
-
-[source,xml,linenums]
-----
-
-----
-
-任务的到期日期也可以使用++TaskService++,或者在++TaskListener++中使用传递的++DelegateTask++修改。
-
-
-[[bpmnUserTaskAssignment]]
-
-
-===== 用户指派
-
-用户任务可以直接指派(assign)给用户。可以定义**humanPerformer**子元素来实现。__humanPerformer__需要**resourceAssignmentExpression**来实际定义用户。目前,只支持**formalExpressions**。
-
-[source,xml,linenums]
-----
-
-
- ...
-
-
-
-
- kermit
-
-
-
-----
-
-**只能指定一个**用户作为任务的__humanPerformer__。在Flowable术语中,这个用户被称作**办理人(assignee)**。拥有办理人的任务,在其他人的任务列表中不可见,而只能在该办理人的**个人任务列表**中看到。
-
-可以通过TaskService获取特定用户办理的任务:
-
-[source,java,linenums]
-----
-List tasks = taskService.createTaskQuery().taskAssignee("kermit").list();
-----
-
-任务也可以放在用户的**候选任务列表**中。在这个情况下,需要使用**potentialOwner(潜在用户)**结构。用法与__humanPerformer__结构类似。请注意需要指定表达式中的每一个元素为用户还是组(引擎无法自行判断)。
-
-[source,xml,linenums]
-----
-
-
- ...
-
-
-
-
- user(kermit), group(management)
-
-
-
-----
-
-可用如下方法获取定义了__potentialOwner__结构的任务:
-
-[source,java,linenums]
-----
- List tasks = taskService.createTaskQuery().taskCandidateUser("kermit");
-----
-
-将获取所有kermit作为**候选用户**的任务,也就是说,表达式含有__user(kermit)__的任务。同时也将获取所有**指派给kermit为其成员的组**的任务(例如,kermit时__management__组的成员,且任务指派给__management__组)。组在运行时解析,并可通过<>管理。
-
-如果并未指定给定字符串是用户还是组,引擎默认其为组。下列代码与__声明group(accountancy)__效果一样。
-
-[source,xml,linenums]
-----
-accountancy
-----
-
-
-[[bpmnUserTaskUserAssignmentExtension]]
-
-
-===== 用于任务指派的Flowable扩展
-
-很明显,当指派关系不复杂时,这种用户与组的指派方式十分笨重。为避免这种复杂性,可以在用户任务上使用<>。
-
-* **assignee(办理人)属性**:这个自定义扩展用于直接将用户指派至用户任务。
-
-[source,xml,linenums]
-----
-
-----
-
-与<>定义的**humanPerformer**结构效果完全相同。
-
-* **candidateUsers(候选用户)属性**:这个自定义扩展用于为任务指定候选用户。
-
-[source,xml,linenums]
-----
-
-----
-
-
-与使用<>定义的**potentialOwner**结构效果完全相同。请注意不需要像在__potentialOwner__中一样,使用__user(kermit)__的声明,因为这个属性只能用于用户。
-
-
-* **candidateGroups(候选组)attribute**:这个自定义扩展用于为任务指定候选组。
-
-[source,xml,linenums]
-----
-
-----
-
-与使用<>定义的**potentialOwner**结构效果完全相同。请注意不需要像在__potentialOwner__中一样,使用__group(management)__的声明,因为这个属性只能用于组。
-
-* 可以定义在一个用户任务上同时定义__candidateUsers__与__candidateGroups__。
-
-请注意:尽管Flowable提供了<>身份管理组件,但并不会检查给定的用户是否实际存在。这是为了便于将Flowable嵌入应用时,与已有的身份管理解决方案进行集成。
-
-[[bpmnUserTaskUserCustomIdentityLinkAssignmentExtension]]
-
-
-===== 自定义身份关联类型
-
-在<>中已经介绍过,BPMN标准支持单个指派用户即**humanPerformer**,或者由一组用户构成**potentialOwners**潜在用户池。另外,Flowable为用户任务定义了<>,用于代表任务的**办理人**或者**候选用户**。
-
-Flowable支持的身份关联(identity link)类型有:
-
-[source,java,linenums]
-----
-public class IdentityLinkType {
- /* Flowable内置角色 */
- public static final String ASSIGNEE = "assignee";
- public static final String CANDIDATE = "candidate";
- public static final String OWNER = "owner";
- public static final String STARTER = "starter";
- public static final String PARTICIPANT = "participant";
-}
-----
-
-
-BPMN标准及Flowable示例中,身份认证是**用户**与**组**。在前一章节提到过,Flowable的身份管理实现并不适用于生产环境,而需要在支持的认证概要下自行扩展。
-
-如果需要添加额外的关联类型,可按照下列语法,使用自定义资源作为扩展元素:
-
-[source,xml,linenums]
-----
-
-
-
-
- user(kermit), group(management)
-
-
-
-
-----
-
-自定义关联表达式添加至__TaskDefinition__类:
-
-[source,java,linenums]
-----
-
-protected Map> customUserIdentityLinkExpressions =
- new HashMap>();
-protected Map> customGroupIdentityLinkExpressions =
- new HashMap>();
-
-public Map> getCustomUserIdentityLinkExpressions() {
- return customUserIdentityLinkExpressions;
-}
-
-public void addCustomUserIdentityLinkExpression(
- String identityLinkType, Set idList) {
-
- customUserIdentityLinkExpressions.put(identityLinkType, idList);
-}
-
-public Map> getCustomGroupIdentityLinkExpressions() {
- return customGroupIdentityLinkExpressions;
-}
-
-public void addCustomGroupIdentityLinkExpression(
- String identityLinkType, Set idList) {
-
- customGroupIdentityLinkExpressions.put(identityLinkType, idList);
-}
-----
-
-这些方法将在运行时,由__UserTaskActivityBehavior__的__handleAssignments__方法调用。
-
-最后,需要扩展__IdentityLinkType__类,以支持自定义身份关联类型:
-
-[source,java,linenums]
-----
-package com.yourco.engine.task;
-
-public class IdentityLinkType extends org.flowable.engine.task.IdentityLinkType {
-
- public static final String ADMINISTRATOR = "administrator";
-
- public static final String EXCLUDED_OWNER = "excludedOwner";
-}
-----
-
-
-[[bpmnUserTaskUserCustomAssignmentTaskListeners]]
-
-
-===== 通过任务监听器自定义指派
-
-如果上面的方式仍不能满足要求,可以在创建事件(create event)上使用<>,调用自定义指派逻辑:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-传递至++TaskListener++的++DelegateTask++,可用于设置办理人与候选用户/组:
-
-[source,java,linenums]
-----
-public class MyAssignmentHandler implements TaskListener {
-
- public void notify(DelegateTask delegateTask) {
- // 在这里执行自定义身份查询
-
- // 然后调用如下命令:
- delegateTask.setAssignee("kermit");
- delegateTask.addCandidateUser("fozzie");
- delegateTask.addCandidateGroup("management");
- ...
- }
-
-}
-----
-
-当使用Spring时,可以按上面章节的介绍使用自定义指派属性,并交由使用<>、带有<>的Spring bean,监听任务__创建__事件。在下面的例子中,通过调用++ldapService++ Spring bean的++findManagerOfEmployee++方法设置办理人。传递的__emp__参数是一个流程变量。
-
-[source,xml,linenums]
-----
-
-----
-
-也可以用于候选用户与组:
-
-[source,xml,linenums]
-----
-
-----
-
-请注意调用方法的返回类型必须是++String++或++Collection++(候选用户或组):
-
-[source,java,linenums]
-----
-public class FakeLdapService {
-
- public String findManagerForEmployee(String employee) {
- return "Kermit The Frog";
- }
-
- public List findAllSales() {
- return Arrays.asList("kermit", "gonzo", "fozzie");
- }
-
-}
-----
-
-
-[[bpmnScriptTask]]
-
-
-==== 脚本任务
-
-[[bpmnScriptTaskDescription]]
-
-
-===== 描述
-
-脚本任务(script task)是自动执行的活动。当流程执行到达脚本任务时,会执行相应的脚本。
-
-
-[[bpmnScriptTaskGraphicalNotation]]
-
-
-===== 图示
-
-脚本任务用左上角有一个小“脚本”图标的标准BPMN 2.0任务(圆角矩形)表示。
-
-image::images/bpmn.scripttask.png[align="center"]
-
-
-[[bpmnScriptTaskXml]]
-
-
-===== XML表示
-
-脚本任务使用**script**与**scriptFormat**元素定义。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-**scriptFormat**属性的值,必须是兼容link:$$http://jcp.org/en/jsr/detail?id=223$$[JSR-223](Java平台脚本)的名字。默认情况下,JavaScript包含在每一个JDK中,因此不需要添加任何JAR文件。如果想使用其它(兼容JSR-223的)脚本引擎,则需要在classpath中添加相应的jar,并使用适当的名字。例如,Flowable单元测试经常使用Groovy,因为其语法与Java十分相似。
-
-请注意Groovy脚本引擎与groovy-jsr223 JAR捆绑在一起。在Groovy 4.0版本以前,脚本引擎是Groovy JAR的一部分。因此,必须添加如下依赖:
-
-[source,xml,linenums]
-----
-
- org.apache.groovy
- groovy-jsr223
- 4.x.x
-
-----
-
-
-[[bpmnScriptTaskVariables]]
-
-
-===== 脚本中的变量
-
-到达脚本引擎的执行中,所有的流程变量都可以在脚本中使用。在这个例子里,脚本变量__'inputArray'__实际上就是一个流程变量(一个integer的数组)。
-
-[source,xml,linenums]
-----
-
-----
-
-也可以简单地调用__execution.setVariable("variableName", variableValue)__,在脚本中设置流程变量。默认情况下,变量不会自动储存(**请注意,在一些早期版本中是会储存的!**)。可以将++scriptTask++的++autoStoreVariables++参数设置为++true++,以自动保存任何在脚本中定义的变量(例如上例中的__sum__)。然而这并不是最佳实践。**最佳实践是显式调用execution.setVariable()**,因为在JDK近期的一些版本中,某些脚本语言不能自动保存变量。查看link:$$http://www.jorambarrez.be/blog/2013/03/25/bug-on-jdk-1-7-0_17-when-using-scripttask-in-activiti/$$[这个链接]了解更多信息。
-
-
-[source,xml,linenums]
-----
-
-----
-
-这个参数的默认值为++false++。也就是说如果在脚本任务定义中忽略这个参数,则脚本声明的所有变量将只在脚本执行期间有效。
-
-在脚本中设置变量的例子:
-
-[source,xml,linenums]
-----
-
-----
-
-请注意:下列名字是保留字,**不能用于**变量名:**out,out:print,lang:import,context,elcontext**。
-
-
-[[bpmnScriptTaskResultValue]]
-
-
-===== 脚本任务的结果
-
-脚本任务的返回值,可以通过为脚本任务定义的__'flowable:resultVariable'__属性设置为流程变量。可以是已经存在的,或者新的流程变量。如果指定为已存在的流程变量,则流程变量的值会被脚本执行的结果值覆盖。如果不指定结果变量名,则脚本结果值将被忽略。
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-在上面的例子中,脚本执行的结果(解析表达式__'#{echo}'__的值),将在脚本完成后,设置为名为__'myVar'__的流程变量。
-
-[[_security]]
-===== 安全性
-
-当使用__javascript__作为脚本语言时,可以使用__“安全脚本(secure scripting)”__。参见<>章节。
-
-
-[[bpmnJavaServiceTask]]
-
-
-==== Java服务任务
-
-[[bpmnJavaServiceTaskDescription]]
-
-
-===== 描述
-
-Java服务任务(Java service task)用于调用Java类。
-
-
-[[bpmnJavaServiceTaskGraphicalNotation]]
-
-
-===== 图示
-
-服务任务用左上角有一个小齿轮图标的圆角矩形表示。
-
-image::images/bpmn.java.service.task.png[align="center"]
-
-
-[[bpmnJavaServiceTaskXML]]
-
-
-===== XML表示
-
-有四种方法声明如何调用Java逻辑:
-
-* 指定实现了JavaDelegate或ActivityBehavior的类
-* 调用解析为委托对象(delegation object)的表达式
-* 调用方法表达式(method expression)
-* 对值表达式(value expression)求值
-
-使用**'flowable:class'**属性提供全限定类名(fully qualified classname),指定流程执行时调用的类。
-
-[source,xml,linenums]
-----
-
-----
-
-
-查看<>章节,了解使用这种类的更多信息。
-
-也可以使用解析为对象的表达式。该对象必须遵循的规则,与使用++flowable:class++创建的对象规则相同(查看<>)。
-
-[source,xml,linenums]
-----
-
-----
-
-++delegateExpressionBean++是一个实现了++JavaDelegate++接口的bean,定义在Spring容器中。
-
-使用**flowable:expression**属性指定需要计算的UEL方法表达式。
-
-[source,xml,linenums]
-----
-
-----
-
-将在名为++printer++的对象上调用++printMessage++方法(不带参数)。
-
-也可以为表达式中使用的方法传递变量。
-
-[source,xml,linenums]
-----
-
-----
-
-将在名为++printer++的对象上调用++printMessage++方法。传递的第一个参数为++DelegateExecution++,名为++execution++,在表达式上下文中默认可用。传递的第二个参数,是当前执行中,名为++myVar++变量的值。
-
-可以使用**flowable:expression**属性指定需要计算的UEL值表达式。
-
-[source,xml,linenums]
-----
-
-----
-
-会调用名为++split++的bean的++ready++参数的getter方法,++getReady++(不带参数)。该对象会被解析为执行的流程变量或(如果可用的话)Spring上下文中的bean。
-
-
-[[bpmnJavaServiceTaskImplementation]]
-
-
-===== 实现
-
-要实现可以在流程执行中调用的类,需要实现__org.flowable.engine.delegate.JavaDelegate__接口,并在__execute__方法中提供所需逻辑。当流程执行到达该活动时,会执行方法中定义的逻辑,并按照BPMN 2.0的默认方法离开活动。
-
-下面是一个Java类的示例,用于将流程变量String改为大写。这个类需要实现__org.flowable.engine.delegate.JavaDelegate__接口,因此需要实现__execute(DelegateExecution)__方法。这个方法就是引擎将调用的方法,需要实现业务逻辑。可以通过link:$$http://flowable.org/javadocs/org/flowable/engine/delegate/DelegateExecution.html$$[DelegateExecution]接口(点击链接获取该接口操作的详细Javadoc)访问流程实例信息,如流程变量等。
-
-[source,java,linenums]
-----
-public class ToUppercase implements JavaDelegate {
-
- public void execute(DelegateExecution execution) {
- String var = (String) execution.getVariable("input");
- var = var.toUpperCase();
- execution.setVariable("input", var);
- }
-
-}
-----
-
-
-请注意:**只会为serviceTask上定义的Java类创建一个实例**。所有流程实例共享同一个类实例,用于调用__execute(DelegateExecution)__。这意味着该类不能有任何成员变量,并需要是线程安全的,因为它可能会在不同线程中同时执行。这也影响了<>的使用方法。(译者注:原文可能较老,不正确。5.21中,flowable:class指定的类,会在流程实例启动时,为每个活动分别进行实例化。不过,当该活动在流程中重复执行,或者为多实例时,使用的都会是同一个类实例。)
-
-在流程定义中引用(如++flowable:class++)的类,**不会在部署时实例化**。只有当流程执行第一次到达该类使用的地方时,才会创建该类的实例。如果找不到这个类,会抛出++FlowableException++。这是因为部署时的环境(更准确的说__classpath__),与实际运行的环境经常不一样。例如当使用__ant__或者Flowable应用中业务存档上传的方式部署的流程,其classpath中不会自动包含流程引用的类。
-
-<>也可以使用实现了__org.flowable.engine.impl.delegate.ActivityBehavior__接口的类。该实现可以访问更强大的引擎功能,例如,可以影响流程的控制流程。请注意这并不是很好的实践,需要避免这么使用。建议只有在高级使用场景下,并且你确知在做什么的时候,才使用__ActivityBehavior__接口。
-
-
-[[serviceTaskFieldInjection]]
-
-
-===== 字段注入
-
-可以为委托类的字段注入值。支持下列注入方式:
-
-* 字符串常量
-* 表达式
-
-如果可以的话,会按照Java Bean命名约定(例如,++firstName++成员使用setter ++setFirstName(...)++),通过委托类的公有setter方法,注入变量。如果该字段没有可用的setter,会直接设置该委托类的私有成员的值。有的环境中,SecurityManagers不允许修改私有字段,因此为想要注入的字段暴露一个公有setter方法,是更安全的做法。
-
-**不论在流程定义中声明的是什么类型的值,注入对象的setter/私有字段的类型,总是++org.flowable.engine.delegate.Expression++。解析表达式后,可以被转型为合适的类型。**
-
-__'flowable:class'__属性支持字段注入。也可以在使用__flowable:delegateExpression__属性时,进行字段注入。然而考虑到线程安全,需要遵循特殊的规则(参见下一章节)。
-
-下面的代码片段展示了如何为类中声明的字段注入常量值。请注意按照BPMN 2.0 XML概要的要求,**在实际字段注入声明前,需要先声明'extensionElements'XML元素**。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-++ToUpperCaseFieldInjected++类有一个字段++text++,为++org.flowable.engine.delegate.Expression++类型。当调用++text.getValue(execution)++时,会返回配置的字符串++Hello World++:
-
-[source,java,linenums]
-----
-public class ToUpperCaseFieldInjected implements JavaDelegate {
-
- private Expression text;
-
- public void execute(DelegateExecution execution) {
- execution.setVariable("var", ((String)text.getValue(execution)).toUpperCase());
- }
-
-}
-----
-
-另外,对于较长文本(例如邮件正文),可以使用__'flowable:string'__子元素:
-
-[source,xml,linenums]
-----
-
-
-
-
- This is a long string with a lot of words and potentially way longer even!
-
-
-
-
-----
-
-可以使用表达式在运行时动态解析注入的值。这种表达式可以使用流程变量,或者(若使用Spring)Spring定义的Bean。在<>中提到过,当服务任务中使用__flowable:class__属性时,该Java类的实例在所有流程实例中共享。要动态地为字段注入值,可以在++org.flowable.engine.delegate.Expression++中注入值或方法表达式,它们会通过++execute++方法传递的++DelegateExecution++计算/调用。
-
-下面的示例类使用了注入的表达式,并使用当前的++DelegateExecution++解析它们。调用__genderBean__方法时传递的是__gender__变量。完整的代码与测试可以在++org.flowable.examples.bpmn.servicetask.JavaServiceTaskTest.testExpressionFieldInjection++中找到
-
-[source,xml,linenums]
-----
-
-
-
-
- ${genderBean.getGenderString(gender)}
-
-
- Hello ${gender == 'male' ? 'Mr.' : 'Mrs.'} ${name}
-
- extensionElements>
- serviceTask>
-----
-
-[source,java,linenums]
-----
-public class ReverseStringsFieldInjected implements JavaDelegate {
-
- private Expression text1;
- private Expression text2;
-
- public void execute(DelegateExecution execution) {
- String value1 = (String) text1.getValue(execution);
- execution.setVariable("var1", new StringBuffer(value1).reverse().toString());
-
- String value2 = (String) text2.getValue(execution);
- execution.setVariable("var2", new StringBuffer(value2).reverse().toString());
- }
-}
-----
-
-
-另外,为避免XML太过冗长,可以将表达式设置为属性,而不是子元素。
-
-[source,xml,linenums]
-----
-
-
-----
-
-[[serviceTaskFieldInjectionThreadSafety]]
-
-===== 字段注入与线程安全
-
-通常情况下,在服务任务中使用Java委托与字段注入是线程安全的。然而,有些情况下不能保证线程安全。这取决于设置,或Flowable运行的环境。
-
-当使用__flowable:class__属性时,使用字段注入总是线程安全的(译者注:仍不完全安全,如对于多实例服务任务,使用的是同一个实例)。对于引用了某个类的每一个服务任务,都会实例化新的实例,并且在创建实例时注入一次字段。在不同的任务或流程定义中多次使用同一个类没有问题。
-
-当使用__flowable:expression__属性时,不能使用字段注入。只能通过方法调用传递变量。总是线程安全的。
-
-当使用__flowable:delegateExpression__属性时,委托实例的线程安全性,取决于表达式解析的方式。如果该委托表达式在多个任务或流程定义中重复使用,并且表达式总是返回相同的示例,则字段注入**不是线程安全的**。让我们看几个例子。
-
-假设表达式为__${factory.createDelegate(someVariable)}__,其中factory为引擎可用的Java bean(例如使用Spring集成时的Spring bean),并在每次表达式解析时创建新的实例。这种情况下,使用字段注入时,没有线程安全性问题:每次表达式解析时,都会注入新实例的字段。
-
-然而,如果表达式为__${someJavaDelegateBean}__,解析为JavaDelegate的实现,并且在创建单例的环境(如Spring)中运行。当在不同的任务或流程定义中使用这个表达式时,表达式总会解析为相同的实例。这种情况下,使用字段注入不是线程安全的。例如:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-这段示例代码有两个服务任务,使用同一个委托表达式,但是__expression__字段填写不同的值。**如果该表达式解析为相同的实例,就会在并发场景下,注入__someField__字段时出现竞争条件**。
-
-最简单的解决方法是:
-
-* 使用表达式代替直接使用Java委托,并将所需数据通过方法参数传递给委托。
-* 或者,在每次委托表达式解析时,返回委托类的新实例。这意味着这个bean的scope必须是**prototype(原型)**(例如在委托类上加上@Scope(SCOPE_PROTOTYPE)注解)。
-
-在Flowable 5.22版本中,可以通过配置流程引擎配置,禁用在委托表达式上使用字段注入。需要设置__delegateExpressionFieldInjectionMode__参数(取__org.flowable.engine.imp.cfg.DelegateExpressionFieldInjectionMode__枚举中的值)。
-
-可使用下列选项:
-
-* **DISABLED(禁用)**:当使用委托表达式时,完全禁用字段注入。不会再尝试进行字段注入。这是最安全的方式,保证线程安全。
-* **COMPATIBILITY(兼容)**:在这个模式下,行为与V5.21之前完全一样:可以在委托表达式中使用字段注入,如果委托类中没有定义该字段,会抛出异常。这是最不线程安全的模式,但可以保证历史版本兼容性,也可以在委托表达式只在一个任务中使用的时候(因此不会产生并发竞争条件),安全使用。
-* **MIXED(混合)**:可以在使用委托表达式时注入,但当委托中没有定义字段时,不会抛出异常。这样可以在部分委托(比如不是单例的实例)中使用注入,而在部分委托中不使用注入。
-
-* **Flowable 5.x版本的默认模式为COMPATIBILITY**。
-* **Flowable 6.x版本的默认模式为MIXED**。
-
-例如,假设使用__MIXED__模式,并使用Spring集成,在Spring配置中定义了如下bean:
-
-[source,xml,linenums]
-----
-
-
-
-----
-
-第一个bean是一般的Spring bean,因此是单例的。第二个bean的scope为__prototype__,因此每次请求这个bean时,Spring容器都会返回一个新实例。
-
-在以下流程定义中:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-有四个服务任务,第一、二个使用__${prototypeDelegateExpressionBean}__委托表达式,第三、四个使用__${singletonDelegateExpressionBean}__委托表达式。
-
-先看原型bean:
-
-[source,java,linenums]
-----
-public class PrototypeDelegateExpressionBean implements JavaDelegate {
-
- public static AtomicInteger INSTANCE_COUNT = new AtomicInteger(0);
-
- private Expression fieldA;
- private Expression fieldB;
- private Expression resultVariableName;
-
- public PrototypeDelegateExpressionBean() {
- INSTANCE_COUNT.incrementAndGet();
- }
-
- @Override
- public void execute(DelegateExecution execution) {
-
- Number fieldAValue = (Number) fieldA.getValue(execution);
- Number fieldValueB = (Number) fieldB.getValue(execution);
-
- int result = fieldAValue.intValue() + fieldValueB.intValue();
- execution.setVariable(resultVariableName.getValue(execution).toString(), result);
- }
-
-}
-----
-
-在运行上面流程定义的流程实例后,__INSTANCE_COUNT__的值为__2__。这是因为每次解析__${prototypeDelegateExpressionBean}__时,都会创建新实例。可以看到三个__Expression__成员字段的注入没有任何问题。
-
-单例bean则有一点区别:
-
-[source,java,linenums]
-----
-public class SingletonDelegateExpressionBean implements JavaDelegate {
-
- public static AtomicInteger INSTANCE_COUNT = new AtomicInteger(0);
-
- public SingletonDelegateExpressionBean() {
- INSTANCE_COUNT.incrementAndGet();
- }
-
- @Override
- public void execute(DelegateExecution execution) {
-
- Expression fieldAExpression = DelegateHelper.getFieldExpression(execution, "fieldA");
- Number fieldA = (Number) fieldAExpression.getValue(execution);
-
- Expression fieldBExpression = DelegateHelper.getFieldExpression(execution, "fieldB");
- Number fieldB = (Number) fieldBExpression.getValue(execution);
-
- int result = fieldA.intValue() + fieldB.intValue();
-
- String resultVariableName = DelegateHelper.getFieldExpression(execution,
- "resultVariableName").getValue(execution).toString();
- execution.setVariable(resultVariableName, result);
- }
-
-}
-----
-
-在对于单例bean,__INSTANCE_COUNT__总是__1__。在这个委托中,没有__Expression__成员字段(使用__MIXED__模式)。而在__COMPATIBILITY__模式下,就会抛出异常,因为需要有成员字段。这个bean也可以使用__DISABLED__模式,但会禁用上面进行了字段注入的原型bean。
-
-在委托的代码里,使用了**org.flowable.engine.delegate.DelegateHelper**。它提供了一些有用的工具方法,用于执行相同的逻辑,并且在单例中是线程安全的。与注入__Expression__不同,它通过__getFieldExpression__读取。这意味着在服务任务的XML里,字段定义与单例bean完全相同。查看上面的XML代码,可以看到定义是相同的,只是实现逻辑不同。
-
-技术提示:__getFieldExpression__直接读取BpmnModel,并在方法执行时创建表达式,因此是线程安全的。
-
-* 在Flowable V5.x版本中,(由于架构缺陷)不能在__ExecutionListener__或__TaskListener__中使用DelegateHelper。要保证监听器的线程安全,仍需使用表达式,或确保每次解析委托表达式时,都创建新实例。
-* 在Flowable V6.x版本中,在__ExecutionListener__或__TaskListener__中可以使用DelegateHelper。例如在V6.x版本中,下列代码可以使用**DelegateHelper**:
-
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-----
-
-其中__testExecutionListener__解析为ExecutionListener接口的一个实现的实例:
-
-[source,java,linenums]
-----
-@Component("testExecutionListener")
-public class TestExecutionListener implements ExecutionListener {
-
- @Override
- public void notify(DelegateExecution execution) {
- Expression inputExpression = DelegateHelper.getFieldExpression(execution, "input");
- Number input = (Number) inputExpression.getValue(execution);
-
- int result = input.intValue() * 100;
-
- Expression resultVarExpression = DelegateHelper.getFieldExpression(execution, "resultVar");
- execution.setVariable(resultVarExpression.getValue(execution).toString(), result);
- }
-
-}
-----
-
-
-[[serviceTaskResultValue]]
-
-
-===== 服务任务的结果
-
-服务执行的返回值(仅对使用表达式的服务任务),可以通过为服务任务定义的__'flowable:resultVariable'__属性设置为流程变量。可以是已经存在的,或者新的流程变量。
-如果指定为已存在的流程变量,则流程变量的值会被服务执行的结果值覆盖。
-如果使用__'flowable:useLocalScopeForResultVariable'__,则会将结果值设置为局部变量。
-如果不指定结果变量名,则服务任务的结果值将被忽略。
-
-[source,xml,linenums]
-----
-
-----
-
-在上例中,服务执行的结果(流程变量或Spring bean中,使用__'myService'__名字所获取的对象,调用__'doSomething()'__方法的返回值),在服务执行完成后,会设置为名为__'myVar'__的流程变量。
-
-[[serviceTaskTriggerable]]
-
-
-===== 可触发
-
-一种常见的模式是发送JMS消息或HTTP调用触发外部服务,然后流程实例进入等待状态。之后外部系统会回复响应,流程实例继续执行下一个活动。在默认的BPMN中,需要使用服务任务和接收任务(receive task)。但是这样会引入竞争条件:外部服务的响应可能会早于流程实例持久化及接收任务激活。为了解决这个问题,Flowable为服务任务增加了triggerable(可触发)属性,可以将服务任务转变为执行服务逻辑,并在继续执行之前等待外部触发的任务。如果在可触发服务任务上同时设置异步(async 为 true),则流程实例会先持久化,然后在异步作业中执行服务任务逻辑。在BPMN XML中,可以这样实现可触发服务任务:
-
-[source,xml,linenums]
-----
-
-----
-
-外部服务可以同步或异步地触发等待中的流程实例。为了避免乐观锁异常,最好使用异步触发。默认情况下,异步作业是排他的,也就是说流程实例会被锁定,以保证流程实例中的其他活动不会影响到触发器的逻辑。可以使用RuntimeService的triggerAsync方法,异步触发等待中的流程实例。当然还是可以使用RuntimeService的trigger方法,同步触发。
-
-[[serviceTaskExceptionHandling]]
-
-
-===== 处理异常
-
-当执行自定义逻辑时,通常需要捕获并在流程中处理特定的业务异常。Flowable提供了多种选择。
-
-[[serviceTaskBpmnErrors]]
-
-
-====== 抛出BPMN错误
-
-可以在服务任务或脚本任务的用户代码中抛出BPMN错误。可以在Java委托、脚本、表达式与委托表达式中,抛出特殊的FlowableException:__BpmnError__。引擎会捕获这个异常,并将其转发至合适的错误处理器,如错误边界事件或错误事件子流程。
-
-[source,java,linenums]
-----
-public class ThrowBpmnErrorDelegate implements JavaDelegate {
-
- public void execute(DelegateExecution execution) throws Exception {
- try {
- executeBusinessLogic();
- } catch (BusinessException e) {
- throw new BpmnError("BusinessExceptionOccurred");
- }
- }
-
-}
-----
-
-构造函数的参数是错误代码。错误代码决定了处理这个错误的错误处理器。参见<>了解如何捕获BPMN错误。
-
-这个机制**只应该用于业务错误**,需要通过流程中定义的错误边界事件或错误事件子流程处理。技术错误应该通过其他异常类型表现,并且通常不在流程内部处理。
-
-[[exceptionMapping]]
-
-====== 异常映射
-
-也可以使用++mapException++扩展,直接将Java异常映射至业务异常(错误)。单映射是最简单的形式:
-
-[source,xml,linenums]
-----
-
-
- org.flowable.SomeException
-
-
-
-----
-
-在上面的代码中,如果服务任务抛出++org.flowable.SomeException++的实例,引擎会捕获该异常,并将其转换为带有给定errorCode的BPMN错误。然后就可以像普通BPMN错误完全一样地处理。其他的异常没有映射,仍将抛出至API调用处。
-
-也可以在单行中使用++includeChildExceptions++属性,映射特定异常的所有子异常。
-
-[source,xml,linenums]
-----
-
-
- org.flowable.SomeException
-
-
-
-----
-
-上面的代码中,Flowable会将++SomeException++的任何直接或间接的子类,转换为带有指定错误代码的BPMN错误。
-当未指定++includeChildExceptions++时,视为“false”。
-
-默认映射最泛用。默认映射是一个不指定类的映射,可以匹配任何Java异常:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-除了默认映射,会按照从上至下的顺序检查映射,使用第一个匹配的映射。只在所有映射都不能成功匹配时使用默认映射。
-只有第一个不指定类的映射会作为默认映射。默认映射忽略++includeChildExceptions++。
-
-
-[[serviceTaskExceptionSequenceFlow]]
-
-
-====== 异常顺序流
-
-<>
-
-
-也可以选择在发生异常时,将流程执行路由至另一条路径。下面是一个例子。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-服务任务有两条出口顺序流,命名为++exception++与++no-exception++。在发生异常时,使用顺序流ID控制流程流向:
-
-[source,java,linenums]
-----
-public class ThrowsExceptionBehavior implements ActivityBehavior {
-
- public void execute(DelegateExecution execution) {
- String var = (String) execution.getVariable("var");
-
- String sequenceFlowToTake = null;
- try {
- executeLogic(var);
- sequenceFlowToTake = "no-exception";
- } catch (Exception e) {
- sequenceFlowToTake = "exception";
- }
- DelegateHelper.leaveDelegate(execution, sequenceFlowToTake);
- }
-
-}
-----
-
-
-[[serviceTaskCallActivitiService]]
-
-
-===== 在JavaDelegate中使用Flowable服务
-
-有的时候,需要在Java服务任务中使用Flowable服务(例如调用活动(call activity)不满足需要的场景下,使用RuntimeService启动流程实例)。
-
-[source,java,linenums]
-----
-public class StartProcessInstanceTestDelegate implements JavaDelegate {
-
- public void execute(DelegateExecution execution) throws Exception {
- RuntimeService runtimeService = Context.getProcessEngineConfiguration().getRuntimeService();
- runtimeService.startProcessInstanceByKey("myProcess");
- }
-
-}
-----
-
-可以使用这个接口访问所有Flowable服务API。
-
-使用这些API调用造成的所有数据变更都在当前事务中。在依赖注入的环境(如Spring或CDI,无论是否使用启用JTA的数据源)下也可以使用这个接口。例如,下面的代码片段与上面的代码具有相同功能,但通过注入而不是__org.flowable.engine.EngineServices__接口获得RuntimeService。
-
-[source,java,linenums]
-----
-@Component("startProcessInstanceDelegate")
-public class StartProcessInstanceTestDelegateWithInjection {
-
- @Autowired
- private RuntimeService runtimeService;
-
- public void startProcess() {
- runtimeService.startProcessInstanceByKey("oneTaskProcess");
- }
-
-}
-----
-
-**重要技术提示:**由于服务调用是在当前事务中完成的,因此在服务任务执行前产生或修改的数据尚未存入数据库。所有API调用都基于数据库数据处理,这意味着这些未提交的修改在服务任务的API调用中“不可见”。
-
-[[bpmnWebserviceTask]]
-
-
-==== Web服务任务
-
-[[bpmnWebserviceTaskDescription]]
-
-
-===== 描述
-
-Web服务任务(Web service task)用于同步地调用外部的Web服务。
-
-[[bpmnWebserviceTaskGraphicalNotation]]
-
-
-===== 图示
-
-Web服务任务与Java服务任务图标一样。
-
-image::images/bpmn.web.service.task.png[align="center"]
-
-
-[[bpmnWebserviceTaskXML]]
-
-
-===== XML表示
-
-使用Web服务之前,需要导入其操作及复杂的类型。可以使用导入标签(import tag)指向Web服务的WSDL,自动处理:
-
-[source,xml,linenums]
-----
-
-----
-
-按照上面的声明,Flowable会导入定义,但不会创建条目定义(item definition)与消息。如果需要调用一个名为'prettyPrint'的方法,则需要先为请求及回复消息创建对应的消息与条目定义:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-----
-
-在声明服务任务前,需要定义实际引用Web服务的BPMN接口与操作。基本上,是定义“接口”与所需的“操作”。对每一个操作都可以重复使用之前定义的“传入”与“传出”消息。例如,下面的声明定义了“counter”接口及“prettyPrintCountOperation”操作:
-
-[source,xml,linenums]
-----
-
-
- tns:prettyPrintCountRequestMessage
- tns:prettyPrintCountResponseMessage
-
-
-----
-
-这样就可以使用##WebService实现,声明Web服务任务,并引用Web服务操作。
-
-[source,xml,linenums]
-----
-
-----
-
-[[bpmnWebserviceTaskIOSpecification]]
-
-
-===== Web服务任务IO规范
-
-除非使用简化方法处理输入与输出数据关联(见下),否则需要为每个Web服务任务声明IO规范,指出任务的输入与输出是什么。这个方法很简单,也兼容BPMN 2.0。在prettyPrint例子中,根据之前声明的条目定义,定义输入与输出:
-
-[source,xml,linenums]
-----
-
-
-
-
- dataInputOfServiceTask
-
-
- dataOutputOfServiceTask
-
-
-----
-
-[[bpmnWebserviceTaskDataInputAssociation]]
-
-
-===== Web服务任务数据输入关联
-
-有两种指定数据输入关联的方式:
-
-* 使用表达式
-* 使用简化方法
-
-使用表达式指定数据输入关联,需要定义源及目标条目,并指定每个条目与字段的关联。下面的例子中,我们针对每个条目,指定prefix与suffix字段:
-
-[source,xml,linenums]
-----
-
- dataInputOfProcess
- dataInputOfServiceTask
-
- ${dataInputOfProcess.prefix}
- ${dataInputOfServiceTask.prefix}
-
-
- ${dataInputOfProcess.suffix}
- ${dataInputOfServiceTask.suffix}
-
-
-----
-
-也可以使用更简单明了的简化方法。'sourceRef'元素是一个Flowable变量名,'targetRef'是条目定义的参数。在下面的例子里,将'PrefixVariable'变量的值关联至'prefix'字段,并将'SuffixVariable'变量的值关联至'suffix'字段。
-
-[source,xml,linenums]
-----
-
- PrefixVariable
- prefix
-
-
- SuffixVariable
- suffix
-
-----
-
-[[bpmnWebserviceTaskDataOutputAssociation]]
-
-
-===== Web服务任务数据输出关联
-
-有两种指定数据输出关联的方式:
-
-
-* 使用表达式
-* 使用简化方法
-
-
-使用表达式指定数据输出关联,需要定义目标变量及源表达式。这种方法很简单,与数据输入关联类似:
-
-[source,xml,linenums]
-----
-
- dataOutputOfProcess
- ${dataOutputOfServiceTask.prettyPrint}
-
-----
-
-也可以使用更简单明了的简化方法。'sourceRef'是条目定义的参数,'targetRef'元素是Flowable变量名。这种方法很简单,与数据输入关联类似:
-
-[source,xml,linenums]
-----
-
- prettyPrint
- OutputVariable
-
-----
-
-[[bpmnBusinessRuleTask]]
-
-
-==== 业务规则任务
-
-[[bpmnBusinessRuleTaskDescription]]
-
-
-===== 描述
-
-业务规则任务(business rule task)用于同步地执行一条或多条规则。Flowable使用名为Drools Expert的Drools规则引擎执行业务规则。目前,业务规则中包含的.drl文件,必须与定义了业务规则服务并执行规则的流程定义一起部署。这意味着流程中使用的所有.drl文件都需要打包在流程BAR文件中,与任务表单等类似。要了解如何为Drools Expert创建业务规则,请访问位于link:$$http://www.jboss.org/drools/documentation$$[JBoss Drools]的Drools文档。
-
-
-如果想要使用自己的规则任务实现,比如希望通过不同方法使用Drools,或者想使用完全不同的规则引擎,则可以使用BusinessRuleTask的class或expression属性。这样它会与link:$$#bpmnJavaServiceTask$$[服务任务]的行为完全相同。
-
-
-[[bpmnBusinessRuleTaskGraphicalNotation]]
-
-
-===== 图示
-
-业务规则任务显示为带有表格图标的圆角矩形。
-
-image::images/bpmn.business.rule.task.png[align="center"]
-
-
-[[bpmnBusinessRuleTaskXML]]
-
-
-===== XML表示
-
-要执行与流程定义在同一个BAR文件中部署的一条或多条业务规则,需要定义输入与结果变量。输入变量可以用流程变量的列表定义,使用逗号分隔。输出变量只能有一个变量名,将执行业务规则后的输出对象存储至流程变量。请注意结果变量会包含对象的List。如果没有指定结果变量名,默认为org.flowable.engine.rules.OUTPUT。
-
-下面的业务规则任务,执行与流程定义一起部署的所有业务规则:
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
-
-
-
-----
-
-也可以将业务规则任务配置为只执行部署的.drl文件中的一组规则。要做到这一点,需要指定规则名字的列表,用逗号分隔。
-
-[source,xml,linenums]
-----
-
-----
-
-这样只会执行rule1与rule2。
-
-也可以定义需要从执行中排除的规则列表。
-
-[source,xml,linenums]
-----
-
-----
-
-这个例子中,除了rule1与rule2之外,其它所有与流程定义一起部署在同一个BAR文件中的规则都会被执行。
-
-前面提到过,还可以自行指定BusinessRuleTask的实现:
-
-[source,xml,linenums]
-----
-
-----
-
-这样配置的业务规则任务与服务任务的行为完全一样,但仍保持业务规则任务的图标,代表在这里处理业务规则。
-
-
-[[bpmnEmailTask]]
-
-
-==== 邮件任务
-
-Flowable让你可以通过自动的邮件服务任务(email task),增强业务流程。可以向一个或多个收信人发送邮件,支持cc,bcc,HTML文本,等等。请注意邮件任务**不是**BPMN 2.0规范的“官方”任务(所以也没有专用图标)。因此,在Flowable中,邮件任务实现为一种特殊的服务任务。
-
-[[bpmnEmailTaskServerConfiguration]]
-
-
-===== 配置邮件服务器
-
-Flowable引擎使用支持SMTP的外部邮件服务器发送邮件。为了发送邮件,引擎需要了解如何连接邮件服务器。可以在__flowable.cfg.xml__配置文件中设置下面的参数:
-
-[options="header"]
-|===============
-|参数|必填?|描述
-|mailServerHost|否|邮件服务器的主机名(如mail.mycorp.com)。默认为++localhost++
-|mailServerPort|是,如果不使用默认端口|邮件服务器的SMTP端口。默认值为__25__
-|mailServerDefaultFrom|否|若用户没有提供地址,默认使用的邮件发件人地址。默认为__flowable@localhost___
-|mailServerUsername|若服务器需要|部分邮件服务器发信时需要进行认证。默认为空。
-|mailServerPassword|若服务器需要|部分邮件服务器发信时需要进行认证。默认为空。
-|mailServerUseSSL|若服务器需要|部分邮件服务器要求ssl通信。默认设置为false。
-|mailServerUseTLS|若服务器需要|部分邮件服务器要求TLS通信(例如gmail)。默认设置为false。
-
-|===============
-
-
-[[bpmnEmailTaskUsage]]
-
-
-===== 定义邮件任务
-
-邮件任务实现为特殊的<>,将服务任务的__type__定义为__'mail'__进行设置。
-
-[source,xml,linenums]
-----
-
-----
-
-邮件任务通过<>配置。这些参数的值可以使用EL表达式,并将在流程执行运行时解析。可以设置下列参数:
-
-
-[options="header"]
-|===============
-|参数|必填?|描述
-|to|是|邮件的收信人。可以使用逗号分隔的列表定义多个接收人
-|from|否|邮件的发信人地址。如果不设置,会使用<>的地址
-|subject|否|邮件的主题
-|cc|否|邮件的抄送人。可以使用逗号分隔的列表定义多个接收人
-|bcc|否|邮件的密送人。可以使用逗号分隔的列表定义多个接收人
-|charset|否|可以指定邮件的字符集,对许多非英语语言很必要。
-|html|否|邮件的HTML文本
-|text|否|邮件的内容,用于纯文本邮件。对于不支持富文本内容的客户端,可以与__html__一起使用。邮件客户端可以回退为显式纯文本格式。
-|htmlVar|否|存储邮件HTML内容的流程变量名。与__html__参数的最大区别,是这个参数会在邮件任务发送前,使用其内容进行表达式替换。
-|textVar|否|存储邮件纯文本内容的流程变量名。与__text__参数的最大区别,是这个参数会在邮件任务发送前,使用其内容进行表达式替换。
-|ignoreException|否|处理邮件失败时,是忽略还是抛出FlowableException。默认设置为false。
-|exceptionVariableName|否|如果设置__ignoreException = true__,而处理邮件失败时,则使用给定名字的变量保存失败信息
-
-|===============
-
-
-[[bpmnEmailTaskExampleUsage]]
-
-
-===== 示例 usage
-
-下面的XML代码片段是使用邮件任务的示例。
-
-[source,xml,linenums]
-----
-
-
-
-
-
-
-
-
-
- Hello ${male ? 'Mr.' : 'Mrs.' } ${recipientName},
-
- As of ${now}, your order has been processed and shipped.
-
- Kind regards,
-
- TheCompany.
-
-