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