Backend Development 15 min read

Introduction to Rule Engines and Their Application in a Car‑Buying Workflow

This article explains what a rule engine is, contrasts it with workflow engines, outlines its benefits, reviews popular Java rule‑engine frameworks, and demonstrates a practical implementation for a second‑hand car buying process using JSON configuration, Spring‑SpEL, and modular Java actions.

HomeTech
HomeTech
HomeTech
Introduction to Rule Engines and Their Application in a Car‑Buying Workflow

1. Rule Engine Introduction

Rule engines evolve from inference engines and are embedded components that separate business decisions from application code by using predefined semantic modules. They accept data input, interpret business rules, and make decisions based on those rules.

Difference between Rule Engine and Process Engine

Rule engines address mutable logic and business coupling, allowing hot‑updates and higher readability, whereas process engines manage multi‑role workflow transitions such as leave or approval processes.

Benefits of Rule Engines

Declarative programming : you describe *what* to do, not *how* to do it.

Separation of logic and data : business logic lives in rules, data stays in domain objects.

Knowledge centralization : rules form an executable knowledge base that is easy to read and document.

Human‑readable rules : if‑then syntax can be close to natural language, enabling non‑technical experts to understand them.

2. Rule Engine Frameworks

Common Java rule‑engine frameworks include Drools, Aviator, EasyRule, and QLExpress. The following images illustrate their comparative features:

3. Rule Engine in a Second‑Hand Car Buying Scenario

Background

The one‑stop car buying service requires multiple steps (viewing, confirming, etc.). Introducing a rule engine abstracts these steps, reduces code duplication, and improves maintainability.

Business Flow

Editing → Confirming → Starting view → Ending view → Completion.

Technical Implementation

The engine is built on EasyRule with two main parts: a reflection‑based rule flow and Spring‑SpEL condition evaluation.

/**
 * 工作流程上下文
 * @author mac
 * @date 2020/10/26
 */
public class WorkFlowContext {
    private BeanProvider beanProvider;
    private Object requestSpec;
    private Object responseSpec;
    private String transitionName;
    public String getTransitionName() { return transitionName; }
    public WorkFlowContext setTransitionName(String transitionName) { this.transitionName = transitionName; return this; }
    public BeanProvider getBeanProvider() { return beanProvider; }
    public WorkFlowContext setBeanProvider(BeanProvider beanProvider) { this.beanProvider = beanProvider; return this; }
    public
T getRequestSpec() { return (T) requestSpec; }
    public WorkFlowContext setRequestSpec(Object requestSpec) { this.requestSpec = requestSpec; return this; }
    public
T getResponseSpec() { return (T) responseSpec; }
    public WorkFlowContext setResponseSpec(Object responseSpec) { this.responseSpec = responseSpec; return this; }
}

Rule definitions are stored in a JSON file (e.g., buyCar.json ) that describes nodes, conditions, and transitions.

{
  "name": "买车流程工作流模板",
  "flow_id": "buyCar",
  "init_data": {"status": 1, "action": 1},
  "nodes": [
    {"name": "payedNode", "desc": "已支付节点", "start": true, "condition": "status == 101", "transitions": [{"name": "CONFIRM_ORDER_ACTION", "to": "editorTakeOrderNode", "action": "confirmOrderAction"}]},
    {"name": "editorTakeOrderNode", "desc": "顾问确认接单节点", "condition": "status == 130", "transitions": [{"name": "CONFIRM_CAR_ACTION", "to": "editorTakeCarNode", "action": "confirmCarAction"}]}
    // ... other nodes omitted for brevity
  ]
}

Base action classes provide common validation and parameter handling, while concrete actions (e.g., ConfirmCarAction ) implement specific business logic.

@Slf4j
@Component("confirmCarAction")
public class ConfirmCarAction extends BaseBuyCarAction {
    @Override
    public Result checkParam(CxmActionOperationVo request, ConsignmentCarOrderRecord record) {
        Result superResult = super.checkParam(request, record);
        if (superResult.isFailure()) return superResult;
        if (!CarOrderRecordStatusEnum.TakeOrder.getValue().equals(record.getStatus())) {
            return Result.createFailureResult("参数错误,不是顾问接单状态", CxmExceptionEnum.PARAM_ILLEGAL.getCode());
        }
        return Result.createSuccessResult();
    }
    @Override
    public void buildParamAfter(CxmActionOperationVo request, ConsignmentCarOrderRecord record) {
        record.setStatus(CarOrderRecordStatusEnum.TakeCar.getValue());
        // build log entry ...
    }
}

The front‑end calls the engine via an HTTP endpoint, passing the action type.

@ApiOperation("确认接单")
@PostMapping("confirmOrder")
public Result confirmOrderAction(@Valid CxmActionOperationVo actionOperationVo) {
    fillUserInfo(actionOperationVo);
    actionOperationVo.setActionType(CxmBuyCarActionEnum.CONFIRM_ORDER_ACTION.getCode());
    return actionExecuteService.actionExecute(actionOperationVo);
}

4. Core Value

Centralized, readable rule definitions enable easier maintenance.

Configuration‑driven logic provides better business extensibility.

Hot‑update capability reduces deployment overhead.

Testing cost drops by ~50% because only action logic needs verification.

Uniform code structure supports agile iteration.

5. Summary

Introducing a rule engine separates complex business rules from code, lowers coupling, improves maintainability, and empowers both developers and business users to evolve functionality quickly and safely.

Javaworkflowbackend developmentconfigurationbusiness rules
HomeTech
Written by

HomeTech

HomeTech tech sharing

0 followers
Reader feedback

How this landed with the community

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