Backend Development 16 min read

Easy Rules Java Rule Engine: Features, Usage, and Real‑World Scenarios

This article introduces the lightweight Easy Rules Java rule engine, explains why traditional if‑else logic is problematic, demonstrates core concepts such as rule, condition, action, and facts, provides step‑by‑step code examples, showcases six practical use‑cases, and shows how to integrate it with Spring Boot and Maven.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Easy Rules Java Rule Engine: Features, Usage, and Real‑World Scenarios

Easy Rules is a simple yet powerful Java rule engine that offers a lightweight framework, an easy‑to‑learn API, POJO‑based development, abstract business rule definition, composite rule creation, and support for expression languages like MVEL and SpEL.

Why Choose Easy Rules

1. Problems with Traditional if‑else Programming

Case 1: Frequent changes in e‑commerce discount rules

Hard‑coded if‑else logic leads to maintenance difficulty, high release risk, and collaboration issues.

// Traditional hard‑coded nightmare
if (user.isVip()) {
    if (order.getAmount() > 200) {
        if (order.getItems().stream().anyMatch(i -> i.isPromotion())) {
            order.applyDiscount(0.8); // VIP discount
        }
    } else if (order.getCreateTime().isAfter(LocalDate.of(2023,11,1))) {
        order.applyDiscount(0.9); // Double‑11 VIP discount
    }
} else {
    // ordinary user logic ...
}

Case 2: Nested IoT alarm conditions

Complex nested conditions make debugging hard, reduce extensibility, and hinder knowledge transfer.

if (temperature > 50 || humidity > 80) {
    if (pressure < 100 && vibration > 5) {
        if (deviceStatus != Status.MAINTENANCE) {
            triggerAlarm(AlarmLevel.CRITICAL);
        }
    }
} else if (runtimeHours > 1000 && !isMaintained) {
    triggerAlarm(AlarmLevel.WARNING);
}
// ... more else‑if branches ...

Advantages of a Lightweight Rule Engine

2. Decoupling and Readability

Rules are separated from business code, can be stored in files or databases, and loaded dynamically without recompilation.

public void refreshRules() {
    List
newRules = ruleLoader.loadFromDB(); // load latest rules
    rulesEngine.fire(new Rules(newRules), facts);
}

Rules become self‑describing documents, support visual decision‑flow graphs, and enable zero‑intrusion extensions.

# discount_rule.yml
name: "老用户回馈规则"
description: "注册超过3年的用户额外折扣"
condition: "user.registerYears >= 3"
actions:
  - "order.applyAdditionalDiscount(0.95)"

Defining Rules

A rule consists of a name, description, priority, facts, condition, and actions. The Rule interface defines evaluate(Facts facts) and execute(Facts facts) .

public interface Rule {
    /** return true if the rule matches the given facts */
    boolean evaluate(Facts facts);
    /** perform actions when the rule matches */
    void execute(Facts facts) throws Exception;
    // getters/setters omitted
}

Rules can be defined via annotations:

@Rule(name = "my rule", description = "my rule description", priority = 1)
public class MyRule {
    @Condition
    public boolean when(@Fact("fact") boolean fact) {
        // my rule conditions
        return true;
    }
    @Action(order = 1)
    public void then(Facts facts) throws Exception {
        // my actions
    }
    @Action(order = 2)
    public void finally(Facts facts) throws Exception {
        // final actions
    }
}

Or programmatically with RuleBuilder :

Rule rule = new RuleBuilder()
        .name("myRule")
        .description("myRuleDescription")
        .priority(3)
        .when(condition)
        .then(action1)
        .then(action2)
        .build();

Defining Facts

Facts are a map of named objects used by conditions and actions.

Facts facts = new Facts();
facts.add("rain", true);

Inject facts with @Fact in rule methods.

@Rule
public class WeatherRule {
    @Condition
    public boolean itRains(@Fact("rain") boolean rain) {
        return rain;
    }
    @Action
    public void takeAnUmbrella(Facts facts) {
        System.out.println("It rains, take an umbrella!");
    }
}

Rule Engine Implementations

From version 3.1, Easy Rules provides DefaultRulesEngine (natural order) and InferenceRulesEngine (iterative inference).

RulesEngine engine = new DefaultRulesEngine();
// or
RulesEngine engine = new InferenceRulesEngine();
engine.fire(rules, facts);

Engine parameters such as skipOnFirstAppliedRule , skipOnFirstFailedRule , and rulePriorityThreshold can be configured via RulesEngineParameters .

RulesEngineParameters params = new RulesEngineParameters()
        .rulePriorityThreshold(10)
        .skipOnFirstAppliedRule(true)
        .skipOnFirstFailedRule(true)
        .skipOnFirstNonTriggeredRule(true);
RulesEngine engine = new DefaultRulesEngine(params);

5‑Minute Quick Start (Hello World)

Add Maven dependency (217 KB core library):

<dependency>
    <groupId>org.jeasy</groupId>
    <artifactId>easy-rules-core</artifactId>
    <version>4.1.0</version>
</dependency>

Run a simple rule that reacts to humidity:

public static void main(String[] args) {
    Facts facts = new Facts();
    facts.put("humidity", 85);
    RulesEngine engine = new DefaultRulesEngine();
    engine.fire(new Rules(new RainRule()), facts);
    // Output: 【智能家居】检测到湿度85%,建议关闭窗户带伞出门!
}

Six Classic Scenarios

E‑commerce promotion system – composite discounts.

IoT alarm system – multi‑level alerts.

Membership level – mixed YAML and annotation rules.

Work order assignment – dynamic dispatch using duty‑table facts.

Risk control – time‑window sliding detection with BloomFilter.

Game combat – combo skill state machine using CircularFifoQueue .

Each scenario includes sample rule definitions, facts, and engine usage.

Spring Boot Integration

@Configuration
public class RuleEngineConfig {
    @Bean
    public RulesEngine rulesEngine() {
        return new DefaultRulesEngine(new Parameters()
                .skipOnFirstNonTriggeredRule(true)
                .priorityThreshold(10));
    }
    @Bean
    public Rules ruleRegistry() throws IOException {
        return new Rules(new AnnotationRuleFactory()
                .create(new ClasspathRuleDefinitionReader(),
                        new ClassPathResource("rules/").getFile()));
    }
    @Bean
    public ApplicationRunner ruleInitializer(RulesEngine engine, Rules rules) {
        return args -> {
            engine.fire(rules, new Facts());
            logger.info("已成功加载{}条规则", rules.size());
        };
    }
}

@RestController
public class PromotionController {
    @Autowired private RulesEngine rulesEngine;
    @Autowired private Rules rules;
    @PostMapping("/apply-rules")
    public Order applyRules(@RequestBody Order order) {
        Facts facts = new Facts();
        facts.put("order", order);
        rulesEngine.fire(rules, facts);
        return order;
    }
}

For production, rules can be hot‑reloaded using @RefreshScope and Spring Cloud Config.

Conclusion

Easy Rules is ideal for quickly implementing business rule engines in small‑to‑medium projects due to its simplicity and flexibility; for more complex or high‑performance requirements, consider stronger engines like Drools.

Javarule engineBackend DevelopmentMavenSpring Bootbusiness rulesEasy Rules
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.