Mastering LiteFlow: Build Elegant Java Workflow Engines for Complex Business Logic
This article introduces LiteFlow, a lightweight Java workflow engine, explains its core features, demonstrates rule syntax for serial, parallel, switch, and conditional orchestration, and provides step‑by‑step integration examples—including Maven dependencies, configuration, component implementation, and controller usage—to simplify complex business processes.
LiteFlow Overview
LiteFlow is a lightweight, powerful Chinese workflow engine framework designed for orchestrating complex component‑based business logic. It allows developers to define business logic in separate components and connect them using concise rule files.
Main features include:
Unified component definition using Spring native @Component annotation.
Lightweight rule files; beginners can learn the expression language in about five minutes.
Support for XML, JSON, and YAML rule file formats.
Flexible orchestration of synchronous and asynchronous processes.
Rule sources can be loaded from local files or Zookeeper, with extensible interfaces.
Hot‑refresh mechanism that applies rule changes without restarting the application.
Broad compatibility with Spring Boot, Spring, or other Java projects.
IDEA Plugin
LiteFlow provides an IDEA plugin LiteFlowX that offers intelligent rule file suggestions, syntax highlighting, navigation between components and rule files, and a toolbox for quick access.
Rule Expressions
Key keywords enable various orchestration patterns:
THEN – Serial execution (e.g., THEN(a, b, c, d);).
WHEN – Parallel execution (e.g., WHEN(a, b, c);).
SWITCH – Switch logic based on a component’s result (e.g., SWITCH(a).to(b, c, d);).
IF – Conditional execution (e.g., IF(x, a);).
ELSE – Equivalent to IF with else branch (e.g., IF(x, a).ELSE(b);).
ELIF – Else‑if chaining (e.g., IF(x1, a).ELIF(x2, b).ELSE(c);).
Sub‑processes can be defined and invoked to keep complex flows clear.
Integration Example
To integrate LiteFlow into a Spring Boot project, add the starter dependency:
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.8.5</version>
</dependency>Configure the rule file location in application.yml:
server:
port: 8580
liteflow:
# Rule file path
rule-source: liteflow/*.el.xmlDefine components by extending NodeComponent and implementing process(). Example of a coupon discount component:
@Component("couponCmp")
public class CouponCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
Long couponId = context.getCouponId();
BigDecimal couponPrice = new BigDecimal(15);
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.subtract(couponPrice);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.COUPON_DISCOUNT,
couponId.toString(), prePrice,
currPrice.subtract(prePrice), currPrice,
PriceTypeEnum.COUPON_DISCOUNT.getName()));
}
@Override
public boolean isAccess() {
return this.getContextBean(PriceContext.class).getCouponId() != null;
}
}Conditional components can extend NodeSwitchComponent and implement processSwitch() to decide the next node based on context data.
@Component("postageCondCmp")
public class PostageCondCmp extends NodeSwitchComponent {
@Override
public String processSwitch() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
return context.isOversea() ? "overseaPostageCmp" : "postageCmp";
}
}Define rule files for sub‑processes and the main flow, for example:
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="promotionChain">
THEN(fullCutCmp, fullDiscountCmp, rushBuyCmp);
</chain>
</flow> <?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="mainChain">
THEN(
checkCmp, slotInitCmp, priceStepInitCmp,
promotionConvertCmp, memberDiscountCmp,
promotionChain, couponCmp,
SWITCH(postageCondCmp).to(postageCmp, overseaPostageCmp),
priceResultCmp, stepPrintCmp
);
</chain>
</flow>Expose an endpoint that invokes the flow via FlowExecutor:
@Controller
public class PriceExampleController {
@Resource
private FlowExecutor flowExecutor;
@RequestMapping(value = "/submit", method = RequestMethod.POST)
@ResponseBody
public String submit(@Nullable @RequestBody String reqData) {
try {
PriceCalcReqVO req = JSON.parseObject(reqData, PriceCalcReqVO.class);
LiteflowResponse response = flowExecutor.execute2Resp("mainChain", req, PriceContext.class);
return response.getContextBean(PriceContext.class).getPrintLog();
} catch (Throwable t) {
t.printStackTrace();
return "error";
}
}
}The shared PriceContext object stores all intermediate data, such as order details, member information, coupon IDs, promotion packs, and price steps, enabling components to read and write without explicit parameter passing.
public class PriceContext {
private String orderNo;
private boolean oversea;
private List<ProductPackVO> productPackList;
private OrderChannelEnum orderChannel;
private String memberCode;
private Long couponId;
private List<PromotionPackVO> promotionPackList;
private List<PriceStepVO> priceStepList = new ArrayList<>();
private BigDecimal originalOrderPrice;
private BigDecimal finalOrderPrice;
private String printLog;
// getters and setters omitted for brevity
}By using LiteFlow, complex business processes become clear, maintainable, and easily extensible, with rule files that are simple to write and hot‑reloadable without restarting the application.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
