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.

macrozheng
macrozheng
macrozheng
Mastering LiteFlow: Build Elegant Java Workflow Engines for Complex Business Logic

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.xml

Define 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javabackend-developmentLiteFlowprocess orchestrationWorkflow Engine
macrozheng
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.