Using a Flow Engine and Plugin Extension for Business Isolation and Extensibility
The article explains why simple code quickly becomes unmanageable in multi‑business systems, introduces workflow engines and plugin extensions as solutions, and demonstrates configuration, node definition, execution, and the underlying Java implementation to achieve clean, isolated, and extensible business logic.
As a good programmer, one should keep solutions simple and avoid over‑design; however, in a middle‑platform (mid‑platform) team, workflow orchestration becomes essential for handling many heterogeneous business lines without littering the code with countless if‑else branches.
The author describes the pain points of code coupling, difficulty of testing across dozens of business flows, and the risk of accidental regressions when adding new business logic.
Two main remedies are proposed: using a flow engine to configure separate execution chains for each business, and employing a plugin extension engine so that each business can implement its own variations.
Configure Flow Execution Chains
In the MemberClub project, the DemoMemberPurchaseExtension demonstrates how different member product purchase processes are configured via distinct flow chains (see screenshot in the original article).
Define Flow Nodes
Each flow node implements process , success , rollback , and callback methods.
Flow Execution
Execution requires a flow context object; invoking FlowChain.execute runs the chain.
Flow Engine Execution Principle
The following Java method shows the internal logic of FlowChain.execute :
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("当前流程:{} 发出 Skip请求,后续流程不再执行", 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执行异常,忽略 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 执行异常,忽略 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执行异常,忽略 name:{}", node.getClass().getSimpleName(), e);
}
}
if (exception != null) {
throw exception;
}
}The engine processes each node sequentially; on exception it rolls back, otherwise it runs success callbacks in reverse order, followed by a final callback step.
For more details and the full source code, see the project repository: https://gitee.com/juejinwuyang/memberclub .
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
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.