Master Workflow Orchestration to Simplify Business Logic with Flow Engines
This article explains why workflow orchestration is essential for isolating business logic in large systems, outlines common pitfalls of tangled if‑else code, and demonstrates how to configure and execute flow chains using a Java flow engine and plugin extensions.
As a good programmer, keep solutions simple and avoid over‑design. I once dismissed workflow orchestration as unnecessary, but working in a middle‑platform team showed its importance for isolating business logic.
When many business lines share a system, adding new features without a workflow engine leads to tangled
if‑elsecode, making maintenance risky and testing impossible.
The main pain points are code isolation and extensibility. Two practical solutions are:
Use a workflow engine to configure separate execution chains for each business scenario.
Use a plugin‑extension engine so each business can implement its own variations.
MemberClub demonstrates extensive use of a workflow engine and plugin‑extension engine to solve these problems.
Configuring the Execution Chain
DemoMemberPurchaseExtension shows how to define three different execution chain configurations for various member products.
Defining Flow Nodes
Each node implements
process,
success,
rollback, and
callbackmethods.
Executing the Flow
Call
FlowChain.executewith a context object to run the chain.
During execution, nodes are linked like a responsibility chain:
processruns sequentially, on exception
rollbackruns, and after all succeed
successruns in reverse order, followed by
callback.
FlowChain.execute Implementation
<code>public <T> void execute(FlowChain<T> chain, T context) {
Exception exception = null;
int index = -1;
for (FlowNode<T> node : chain.getNodes()) {
try {
node.process(context);
index++;
} catch (Exception e) {
if (e instanceof SkipException) {
CommonLog.warn("Current flow:{} sent Skip request, stop later flows", node.getClass().getSimpleName());
break;
}
exception = e;
break;
}
}
if (exception != null) {
for (int i = index; i >= 0; i--) {
FlowNode<T> node = chain.getNodes().get(i);
try {
node.rollback(context, exception);
} catch (Exception e) {
CommonLog.error("rollback execution exception, ignore name:{}", node.getClass().getSimpleName(), e);
}
}
} else {
for (int i = index; i >= 0; i--) {
FlowNode<T> node = chain.getNodes().get(i);
try {
node.success(context);
} catch (Exception e) {
CommonLog.error("success execution exception, ignore name:{}", node.getClass().getSimpleName(), e);
}
}
}
for (int i = index; i >= 0; i--) {
FlowNode<T> node = chain.getNodes().get(i);
try {
node.callback(context, exception);
} catch (Exception e) {
CommonLog.error("callback execution exception, ignore name:{}", node.getClass().getSimpleName(), e);
}
}
if (exception != null) {
throw exception;
}
}
</code>Project Source
Source code: https://gitee.com/juejinwuyang/memberclub
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.