Embedded Workflow Orchestration with Spring Boot and Flowable BPMN

A comprehensive guide to embedding BPMN 2.0 workflow orchestration inside Spring Boot applications using Flowable, enabling sophisticated business process automation with data engineering pipeline patterns.

GT
Gonnect Team
January 18, 202412 min readView on GitHub
Spring BootFlowableBPMN

Introduction

Modern enterprise applications often require sophisticated workflow orchestration to manage complex business processes. Whether you are building data engineering pipelines, approval workflows, or multi-step processing systems, embedding a workflow engine directly into your application provides flexibility, auditability, and separation of concerns that procedural code cannot match.

The spring-flowable project demonstrates how to embed a BPMN 2.0 workflow engine inside a Spring Boot application using Flowable, enabling declarative workflow definitions that execute as part of your microservice architecture.

Key Insight: Embedding Flowable in Spring Boot gives you the power of a full BPM engine with the simplicity of a self-contained microservice.

What is Flowable?

Flowable is a lightweight, open-source business process engine written in Java. It implements the BPMN 2.0 specification and provides:

  • Process Definition: Define workflows using industry-standard BPMN 2.0 notation
  • Process Execution: Execute complex workflows with parallel paths, loops, and conditional logic
  • State Management: Automatic persistence and recovery of process state
  • Integration: Seamless Spring Boot integration with auto-configuration

Why Embedded Workflow Engines?

Traditional workflow engines run as standalone servers, requiring additional infrastructure and network communication. Embedded engines offer distinct advantages:

AspectStandalone EngineEmbedded Engine
DeploymentSeparate serviceSingle JAR
LatencyNetwork round-tripIn-process calls
TransactionsDistributedLocal ACID
ScalingCentralizedPer-service
ComplexityHigherLower

Architecture Overview

The spring-flowable project implements a data engineering workflow pattern where different processing steps execute based on the type of execution:

Microservices Architecture

Loading diagram...

This architecture demonstrates a loop-based workflow where:

  1. The process evaluates the execution type
  2. Executes the appropriate step (Load, Move, or Process)
  3. Checks if there is more work to be done
  4. Continues looping or completes
  5. Handles exceptions by sending notification emails

Project Structure

The project follows standard Spring Boot conventions with Flowable integration:

spring-flowable/
├── src/
│   └── main/
│       ├── java/com/gonnect/flowable/
│       │   ├── SpringFlowableApplication.java
│       │   ├── FlowService.java
│       │   ├── LoadService.java
│       │   ├── MoveService.java
│       │   └── ProcessService.java
│       └── resources/
│           └── processes/
│               └── data-navigator-flows.bpmn20.xml
├── pom.xml
└── flow.png

Core Dependencies

The project uses Flowable's Spring Boot starter for seamless integration:

<dependencies>
    <!-- Spring Boot Core -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- Flowable Process Engine -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-spring-boot-starter-process</artifactId>
        <version>6.4.1</version>
    </dependency>

    <!-- Flowable IDM for Identity Management -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-idm-spring</artifactId>
        <version>6.4.1</version>
    </dependency>
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-idm-spring-configurator</artifactId>
        <version>6.4.1</version>
    </dependency>

    <!-- Groovy Scripting Support -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-groovy-script-static-engine</artifactId>
        <version>6.4.1</version>
    </dependency>

    <!-- Embedded Database -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>

Understanding the Implementation

The Main Application

The Spring Boot application demonstrates how to start process instances programmatically:

@SpringBootApplication
public class SpringFlowableApplication {

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

    @Bean
    CommandLineRunner basics(final RuntimeService runtimeService) {
        return new CommandLineRunner() {
            @Override
            public void run(String... strings) throws Exception {
                // Start the waiter process
                runtimeService.startProcessInstanceByKey(
                    "waiter",
                    Collections.singletonMap("customerId", (Object) 243L)
                );

                // Start the data navigator workflow
                runtimeService.startProcessInstanceByKey(
                    "data-navigator-flows",
                    Collections.singletonMap("execution", "1")
                );
            }
        };
    }
}

The RuntimeService is Flowable's primary API for starting and managing process instances. Process variables (like customerId and execution) are passed as a map and become available throughout the workflow.

The Flow Service

The FlowService acts as a decision service, determining which path the workflow should take:

@Service
public class FlowService {

    private boolean isMoveStep;
    private boolean isProcessStep;
    private boolean isLoadStep = true;
    private boolean isException;
    private boolean isNextDataEngineeringFlow;

    public boolean isMoveStep(String execution) {
        System.out.println("isMoveStep = " + isMoveStep);
        return isMoveStep;
    }

    public boolean isProcessStep(String execution) {
        System.out.println("isProcessStep = " + isProcessStep);
        return isProcessStep;
    }

    public boolean isLoadStep(String execution) {
        System.out.println("isLoadStep = " + isLoadStep);
        return isLoadStep;
    }

    public boolean isException(String execution) {
        System.out.println("isException = " + isException);
        return isException;
    }

    public boolean isNextDataEngineeringFlow(String execution) {
        System.out.println("isNextDataEngineeringFlow = " + isNextDataEngineeringFlow);
        return isNextDataEngineeringFlow;
    }
}

This service is invoked by BPMN gateway conditions to route the workflow. In production, these decisions would be based on actual business logic, database queries, or external service calls.

Processing Steps

Each processing step is a simple Spring service that Flowable invokes via service tasks:

@Service
public class LoadService {
    public void execute(String execution) {
        System.out.println("LoadService#execute(execution)");
        // Implement data loading logic
    }
}

@Service
public class MoveService {
    public void execute(String execution) {
        System.out.println("MoveService#execute(execution)");
        // Implement data movement logic
    }
}

@Service
public class ProcessService {
    public void execute(String execution) {
        System.out.println("ProcessService#execute(execution)");
        // Implement data processing logic
    }
}

BPMN Process Definition

The workflow is defined in a BPMN 2.0 XML file that Flowable automatically deploys on startup. Here is a conceptual representation of the data navigator flow:

Microservices Architecture

Loading diagram...

BPMN Elements Used

ElementPurpose
Start EventEntry point for the process
Exclusive GatewayDecision point (XOR logic)
Service TaskInvokes Spring beans
End EventProcess completion
Sequence FlowConnects elements with conditions

Data Engineering Pipeline Pattern

The spring-flowable project demonstrates a common data engineering pattern where different operations execute based on context:

Microservices Architecture

Loading diagram...

This pattern provides:

  • Separation of Concerns: Each step handles one responsibility
  • Restartability: Failed workflows resume from the last successful step
  • Visibility: Process state is queryable at any time
  • Auditability: Full history of workflow execution

Advanced Flowable Features

Process Variables

Pass and access data throughout the workflow:

// Starting with variables
Map<String, Object> variables = new HashMap<>();
variables.put("customerId", 243L);
variables.put("orderAmount", 1500.00);
runtimeService.startProcessInstanceByKey("orderProcess", variables);

// Accessing in a service task
@Service
public class OrderProcessor {
    public void process(DelegateExecution execution) {
        Long customerId = (Long) execution.getVariable("customerId");
        Double amount = (Double) execution.getVariable("orderAmount");
        // Process the order
    }
}

Async Execution

For long-running tasks, enable asynchronous execution:

<serviceTask id="longRunningTask"
             flowable:async="true"
             flowable:delegateExpression="${longRunningService}"/>

Event Listeners

React to process events:

@Component
public class ProcessEventListener implements FlowableEventListener {

    @Override
    public void onEvent(FlowableEvent event) {
        if (event.getType() == FlowableEngineEventType.PROCESS_COMPLETED) {
            ProcessInstance instance = ((FlowableProcessEvent) event)
                .getProcessInstance();
            log.info("Process {} completed", instance.getId());
        }
    }
}

Running the Application

Clone and run the application:

# Clone the repository
git clone https://github.com/mgorav/spring-flowable.git
cd spring-flowable

# Build with Maven
./mvnw clean install

# Run the application
./mvnw spring-boot:run

On startup, Flowable automatically:

  1. Creates the necessary database tables in H2
  2. Deploys BPMN process definitions from resources/processes/
  3. Makes the RuntimeService available for process management

Monitoring and Management

Flowable provides comprehensive APIs for process management:

@RestController
@RequestMapping("/api/processes")
public class ProcessController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @GetMapping("/running")
    public List<ProcessInstanceInfo> getRunningProcesses() {
        return runtimeService.createProcessInstanceQuery()
            .active()
            .list()
            .stream()
            .map(this::toInfo)
            .collect(Collectors.toList());
    }

    @GetMapping("/history")
    public List<HistoricProcessInstanceInfo> getHistory() {
        return historyService.createHistoricProcessInstanceQuery()
            .finished()
            .orderByProcessInstanceEndTime()
            .desc()
            .list()
            .stream()
            .map(this::toHistoryInfo)
            .collect(Collectors.toList());
    }
}

Best Practices

Process Design

  1. Keep processes simple: Break complex workflows into sub-processes
  2. Use meaningful IDs: Process and task IDs should be descriptive
  3. Handle exceptions: Include error boundary events and compensation handlers
  4. Version processes: Use deployment versioning for upgrades

Integration Patterns

  1. Delegate to Spring beans: Use delegateExpression for service tasks
  2. Use async where appropriate: Long-running tasks should be async
  3. Leverage events: React to process events for monitoring and integration
  4. Test thoroughly: Use Flowable's testing support
@SpringBootTest
public class WorkflowTest {

    @Autowired
    private RuntimeService runtimeService;

    @Test
    public void testDataNavigatorFlow() {
        ProcessInstance instance = runtimeService
            .startProcessInstanceByKey("data-navigator-flows",
                Collections.singletonMap("execution", "1"));

        assertNotNull(instance);
        // Assert process completed successfully
    }
}

Conclusion

The spring-flowable project demonstrates the power of embedding BPMN workflow orchestration directly into Spring Boot applications. This approach offers:

  • Simplified Deployment: Single JAR with workflow capabilities
  • Transactional Consistency: Workflow state participates in local transactions
  • Spring Integration: Seamless injection of Spring beans into workflow tasks
  • Standardization: BPMN 2.0 compliance for industry-standard process modeling
  • Flexibility: Suitable for data engineering pipelines, approval workflows, and complex business processes

By leveraging Flowable's lightweight engine with Spring Boot's auto-configuration, developers can implement sophisticated workflow orchestration without the overhead of managing separate BPM infrastructure.


Further Reading