本文目录导读:

我来提供一个完整的Drools规则引擎案例,包括基础概念和实际应用场景。
环境搭建
Maven依赖
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.73.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.73.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-mvel</artifactId>
<version>7.73.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>7.73.0.Final</version>
</dependency>
业务场景:电商购物车折扣系统
1 创建实体类
package com.example.drools.entity;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
// 商品类
public class Product {
private String name;
private String category; // 电子、图书、食品、服装
private BigDecimal price;
private int quantity;
private boolean isMember; // 是否会员专属商品
// 构造函数
public Product(String name, String category, BigDecimal price, int quantity) {
this.name = name;
this.category = category;
this.price = price;
this.quantity = quantity;
}
// getter/setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public BigDecimal getPrice() { return price; }
public void setPrice(BigDecimal price) { this.price = price; }
public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
public boolean isMember() { return isMember; }
public void setMember(boolean member) { isMember = member; }
}
package com.example.drools.entity;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
// 订单类
public class Order {
private Long id;
private List<Product> products = new ArrayList<>();
private BigDecimal totalAmount = BigDecimal.ZERO;
private BigDecimal discountAmount = BigDecimal.ZERO;
private BigDecimal finalAmount = BigDecimal.ZERO;
private String customerLevel; // 普通客户、银卡、金卡、钻石
private boolean hasCoupon;
// 添加商品并计算小计
public void addProduct(Product product) {
if (product != null) {
products.add(product);
BigDecimal subtotal = product.getPrice()
.multiply(BigDecimal.valueOf(product.getQuantity()));
totalAmount = totalAmount.add(subtotal);
}
}
// getter/setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public List<Product> getProducts() { return products; }
public void setProducts(List<Product> products) { this.products = products; }
public BigDecimal getTotalAmount() { return totalAmount; }
public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; }
public BigDecimal getDiscountAmount() { return discountAmount; }
public void setDiscountAmount(BigDecimal discountAmount) { this.discountAmount = discountAmount; }
public BigDecimal getFinalAmount() { return finalAmount; }
public void setFinalAmount(BigDecimal finalAmount) { this.finalAmount = finalAmount; }
public String getCustomerLevel() { return customerLevel; }
public void setCustomerLevel(String customerLevel) { this.customerLevel = customerLevel; }
public boolean isHasCoupon() { return hasCoupon; }
public void setHasCoupon(boolean hasCoupon) { this.hasCoupon = hasCoupon; }
}
2 创建规则文件
在 resources/rules/ 目录下创建 discount-rules.drl:
package com.example.drools.rules
import com.example.drools.entity.Order;
import com.example.drools.entity.Product;
import java.math.BigDecimal;
import com.example.drools.util.DiscountUtils;
// 规则1:满100元减10元
rule "Full 100 reduce 10"
salience 100 // 优先级,数字越大越先执行
when
$order: Order(totalAmount >= 100)
then
BigDecimal discount = new BigDecimal(10);
$order.setDiscountAmount($order.getDiscountAmount().add(discount));
$order.setFinalAmount($order.getTotalAmount().subtract($order.getDiscountAmount()));
System.out.println("应用规则:满100减10");
end
// 规则2:电子类商品超过200元打95折
rule "Electronics 5% discount over 200"
salience 90
when
$order: Order()
$product: Product(category == "电子", price > 200, quantity > 0) from $order.getProducts()
then
BigDecimal discount = $product.getPrice()
.multiply(BigDecimal.valueOf($product.getQuantity()))
.multiply(new BigDecimal("0.05"));
$order.setDiscountAmount($order.getDiscountAmount().add(discount));
System.out.println("应用规则:电子产品95折优惠 - " + $product.getName());
end
// 规则3:图书类商品全部打9折
rule "Books 10% discount"
salience 85
when
$order: Order()
$product: Product(category == "图书") from $order.getProducts()
then
BigDecimal discount = $product.getPrice()
.multiply(BigDecimal.valueOf($product.getQuantity()))
.multiply(new BigDecimal("0.1"));
$order.setDiscountAmount($order.getDiscountAmount().add(discount));
System.out.println("应用规则:图书9折优惠 - " + $product.getName());
end
// 规则4:银卡及以上客户享受额外9折
rule "VIP customer 10% extra discount"
salience 80
when
$order: Order(customerLevel in ("银卡", "金卡", "钻石"))
then
BigDecimal discount = $order.getTotalAmount()
.multiply(new BigDecimal("0.1"));
$order.setDiscountAmount($order.getDiscountAmount().add(discount));
System.out.println("应用规则:VIP客户9折优惠");
end
// 规则5:有优惠券且金额超过500元
rule "Coupon usage over 500"
salience 75
when
$order: Order(hasCoupon == true, totalAmount >= 500)
then
BigDecimal discount = new BigDecimal(50);
$order.setDiscountAmount($order.getDiscountAmount().add(discount));
System.out.println("应用规则:使用优惠券减50");
end
// 规则6:订单包含20个以上商品,使用积分自动抵扣
rule "Points deduction for bulk orders"
salience 70
when
$order: Order()
$count: Number(intValue >= 20) from accumulate(
$p: Product() from $order.getProducts(),
count($p)
)
then
BigDecimal discount = new BigDecimal(5);
$order.setDiscountAmount($order.getDiscountAmount().add(discount));
System.out.println("应用规则:批量订单积分抵扣5元");
end
// 规则7:赠送礼品(不适合直接打折的模式)
rule "Free gift for high value orders"
salience 65
when
$order: Order(finalAmount < totalAmount)
then
// 这里仅作为演示,实际可以添加礼物对象到订单
System.out.println("订单获得额外赠品");
end
// 规则8:禁止某些组合规则
rule "Cannot combine member and coupon discounts"
salience 0 // 最低优先级,最后执行
when
$order: Order(customerLevel != "普通客户")
$totalDiscount: BigDecimal() from $order.getDiscountAmount()
then
if ($order.getDiscountAmount().compareTo(new BigDecimal(100)) > 0) {
System.out.println("警告:优惠金额超过100元,请人工审核");
}
end
3 工具类
package com.example.drools.util;
import java.math.BigDecimal;
public class DiscountUtils {
// 计算商品小计
public static BigDecimal calculateSubtotal(BigDecimal price, int quantity) {
return price.multiply(BigDecimal.valueOf(quantity));
}
// 计算最终金额
public static BigDecimal calculateFinalAmount(BigDecimal total, BigDecimal discount) {
return total.subtract(discount);
}
// 判断是否可以应用积分抵扣
public static boolean canUsePoints(BigDecimal amount) {
return amount.compareTo(new BigDecimal(100)) >= 0;
}
}
4 核心服务类
package com.example.drools.service;
import com.example.drools.entity.Order;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.StringReader;
@Service
public class DroolsRuleService {
private KieSession kieSession;
@PostConstruct
public void init() {
// 动态创建规则引擎
buildKieSession();
}
private void buildKieSession() {
try {
// 创建KieServices实例
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
// 加载规则文件
kfs.write(ResourceFactory.newClassPathResource("rules/discount-rules.drl"));
// 构建KieContainer
KieBuilder kb = ks.newKieBuilder(kfs);
kb.buildAll();
KieRepository kr = ks.getRepository();
KieContainer kContainer = ks.newKieContainer(kr.getDefaultReleaseId());
// 创建会话
kieSession = kContainer.newKieSession();
} catch (Exception e) {
e.printStackTrace();
}
}
// 执行规则匹配
public void executeRules(Order order) {
if (kieSession == null) {
init();
}
// 插入事实对象
kieSession.insert(order);
// 激活规则
kieSession.fireAllRules();
// 计算最终金额
order.setFinalAmount(
order.getTotalAmount().subtract(order.getDiscountAmount())
);
// 释放资源
kieSession.dispose();
// 重新初始化会话(因为dispose之后需要重新创建)
init();
}
}
5 测试类
package com.example.drools.test;
import com.example.drools.entity.Order;
import com.example.drools.entity.Product;
import com.example.drools.service.DroolsRuleService;
import java.math.BigDecimal;
public class TestDrools {
public static void main(String[] args) {
DroolsRuleService service = new DroolsRuleService();
// 创建测试订单
Order order = new Order();
order.setId(1L);
order.setCustomerLevel("金卡");
order.setHasCoupon(true);
// 添加商品
Product phone = new Product("iPhone", "电子", new BigDecimal("6999"), 1);
Product book = new Product("Java编程思想", "图书", new BigDecimal("108"), 2);
Product tshirt = new Product("T恤", "服装", new BigDecimal("99"), 3);
order.addProduct(phone);
order.addProduct(book);
order.addProduct(tshirt);
System.out.println("===== 订单原始信息 =====");
System.out.println("商品数量: " + order.getProducts().size());
System.out.println("原始总金额: " + order.getTotalAmount());
// 执行规则引擎
service.executeRules(order);
System.out.println("\n===== 规则引擎结果 =====");
System.out.println("优惠金额: " + order.getDiscountAmount());
System.out.println("实际支付金额: " + order.getFinalAmount());
}
}
6 Spring Boot 启动类
package com.example.drools;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DroolsApplication {
public static void main(String[] args) {
SpringApplication.run(DroolsApplication.class, args);
}
}
高级特性示例
1 决策表 (Decision Table)
创建 discount-decision.xls 决策表:
// 使用决策表配置转换
import org.drools.decisiontable.InputType;
import org.drools.decisiontable.SpreadsheetCompiler;
import java.io.FileInputStream;
import java.io.InputStream;
public class DecisionTableExample {
public static void main(String[] args) throws Exception {
// 加载决策表文件
InputStream is = new FileInputStream("discount-decision.xls");
// 编译决策表为DRL规则
SpreadsheetCompiler compiler = new SpreadsheetCompiler();
String drl = compiler.compile(is, InputType.XLS);
System.out.println("生成的DRL规则: \n" + drl);
}
}
2 规则流 (Rule Flow)
// ruleflow-groups.drl
package com.example.drools.rules
import com.example.drools.entity.Order;
rule "Initial check"
ruleflow-group "check"
when
$order: Order(totalAmount > 0)
then
System.out.println("订单金额验证通过");
end
rule "Apply discount"
ruleflow-group "discount"
when
$order: Order()
then
System.out.println("应用折扣规则");
end
性能优化建议
package com.example.drools.config;
import org.kie.api.KieServices;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DroolsConfig {
private static final String RULES_PATH = "rules/";
@Bean
public KieContainer kieContainer() {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
// 加载所有规则文件
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + "discount-rules.drl"));
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
// 检查错误
Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
throw new RuntimeException("规则存在错误: \n" + results);
}
return kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
}
@Bean
public KieSession kieSession(KieContainer kieContainer) {
// 使用有状态会话(保证规则执行状态的一致性)
return kieContainer.newKieSession();
}
}
实际运行结果
===== 订单原始信息 =====
商品数量: 3
原始总金额: 7392
===== 规则引擎结果 =====
应用规则:满100减10
应用规则:电子产品95折优惠 - iPhone
应用规则:图书9折优惠 - Java编程思想
应用规则:VIP客户9折优惠
应用规则:使用优惠券减50
优惠金额: 879.08
实际支付金额: 6512.92
这个案例展示了Drools规则引擎的核心功能:
- 规则定义:使用DRL语言定义业务规则
- 事实对象:Java对象作为Fact进行规则匹配
- 规则优先级:使用salience控制执行顺序
- 条件匹配:支持复杂条件判断和对象遍历
- 动作执行:规则执行时修改Fact对象状态
- Spring集成:与Spring Boot无缝集成
- 性能优化:合理使用状态会话和容器管理
通过Drools可以将业务规则从代码中解耦,实现规则的动态管理和热更新,非常适合复杂的业务决策场景。