植木的法则植木耕助
一、环境准备与核心依赖安装
在开始构建规则引擎前,你需要一个干净的开发环境。我们将使用Java作为后端语言,Spring Boot作为框架。
1.1 基础环境配置
确保你的机器上已经安装了以下软件,并配置好环境变量。
- Java 11或更高版本:在终端执行
java -version验证。 - Maven 3.6+:执行
mvn -v验证。 - IDE(如IntelliJ IDEA或Eclipse):本文使用IDEA社区版。
1.2 创建Spring Boot项目并引入依赖
打开IDEA,通过Spring Initializr创建一个新项目,或使用以下命令生成:
curl https://start.spring.io/starter.zip -d dependencies=web,data-jpa,h2 -d javaVersion=11 -d type=maven-project -d bootVersion=2.7.0 -o rule-engine.zip
解压后,用IDEA打开项目。在pom.xml文件中,添加规则引擎核心依赖:
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-mvel</artifactId>
<version>4.1.0</version>
</dependency>
保存文件,IDEA会自动下载依赖。如果使用命令行,执行mvn clean install。
二、定义你的第一条业务规则
规则引擎的核心是“规则”。我们以一个电商折扣场景为例,当用户订单金额满100元时,自动减免10元。
2.1 创建规则实体类
在src/main/java/com/example/ruleengine/model目录下,创建Order.java:
package com.example.ruleengine.model;
public class Order {
private String orderId;
private Double amount;
private Double discount = 0.0;
// 生成Getter和Setter方法(此处省略,实际开发中请使用Lombok或手动生成)
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public Double getAmount() { return amount; }
public void setAmount(Double amount) { this.amount = amount; }
public Double getDiscount() { return discount; }
public void setDiscount(Double discount) { this.discount = discount; }
}
2.2 实现具体的规则逻辑
在src/main/java/com.example.ruleengine.rule目录下,创建OrderDiscountRule.java:
package com.example.ruleengine.rule;
import com.example.ruleengine.model.Order;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Rule;
@Rule(name = “订单满减规则”, description = “当订单金额大于等于100元时,减免10元”)
public class OrderDiscountRule {
@Condition
public boolean when(Order order) {
// 条件判断:订单金额是否 >= 100
return order.getAmount() != null && order.getAmount() >= 100;
}
@Action
public void then(Order order) {
// 执行动作:应用折扣
order.setDiscount(10.0);
System.out.println(“规则触发:订单” + order.getOrderId() + “符合满减条件,已减免10元。”);
}
}
关键点:@Condition方法必须返回布尔值,@Action方法执行具体操作。方法参数Order order是引擎传入的事实对象。
三、组装并执行规则引擎
规则定义好后,需要将它们注册到引擎中,并传入事实数据触发计算。
3.1 创建规则引擎配置类
在src/main/java/com.example.ruleengine/config目录下,创建RuleEngineConfig.java:
package com.example.ruleengine.config;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RuleEngineConfig {
@Bean
public RulesEngine rulesEngine() {
// 创建规则引擎实例,可配置参数
RulesEngine rulesEngine = new DefaultRulesEngine();
// 可以在此处设置引擎参数,例如:
// ((DefaultRulesEngine) rulesEngine).setSkipOnFirstAppliedRule(true);
return rulesEngine;
}
}
3.2 编写服务类触发规则执行
在src/main/java/com.example.ruleengine/service目录下,创建RuleEngineService.java:
package com.example.ruleengine.service;
import com.example.ruleengine.model.Order;
import com.example.ruleengine.rule.OrderDiscountRule;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RuleEngineService {
@Autowired
private RulesEngine rulesEngine;
public Order applyRules(Order order) {
// 1. 创建事实集合,放入需要判断的数据对象
Facts facts = new Facts();
facts.put(“order”, order); // “order”是事实名称,在复杂规则中用于引用
// 2. 创建规则集合,并注册我们定义的规则
Rules rules = new Rules();
rules.register(new OrderDiscountRule());
// 3. 触发规则引擎执行
rulesEngine.fire(rules, facts);
// 4. 返回处理后的订单对象
return order;
}
}
四、创建REST接口进行测试
为了验证规则引擎是否工作,我们创建一个简单的HTTP接口。
4.1 创建控制器
在src/main/java/com.example.ruleengine/controller目录下,创建OrderController.java:
package com.example.ruleengine.controller;
import com.example.ruleengine.model.Order;
import com.example.ruleengine.service.RuleEngineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@Autowired
private RuleEngineService ruleEngineService;
@PostMapping(“/api/order/applyRules”)
public Order applyRules(@RequestBody Order order) {
// 直接调用服务层,触发规则计算
return ruleEngineService.applyRules(order);
}
}
4.2 使用工具进行接口测试
启动Spring Boot应用(运行Application类的main方法)。使用Postman或curl命令测试:
- 请求URL:
POST http://localhost:8080/api/order/applyRules - 请求头:
Content-Type: application/json - 请求体(JSON):
{
“orderId”: “ORD202309280001”,
“amount”: 150.0
}
你将收到如下响应,表示规则已生效:
{
“orderId”: “ORD202309280001”,
“amount”: 150.0,
“discount”: 10.0
}
同时,在应用控制台会看到打印的日志:“规则触发:订单ORD202309280001符合满减条件,已减免10元。”
五、进阶:实现动态规则与规则优先级
静态编码的规则不便于管理。接下来,我们将规则配置到数据库,实现动态加载。
5.1 设计规则表结构
在src/main/resources/schema.sql中创建表(使用H2内存数据库):
CREATE TABLE business_rule (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
rule_name VARCHAR(100) NOT NULL,
rule_condition VARCHAR(500) NOT NULL,
rule_action VARCHAR(500) NOT NULL,
priority INT DEFAULT 0,
enabled BOOLEAN DEFAULT true
);
插入一条规则数据到src/main/resources/data.sql:
INSERT INTO business_rule (rule_name, rule_condition, rule_action, priority) VALUES
(‘VIP用户折扣规则’, ‘order.getAmount() > 200 && order.getUserLevel().equals(“VIP”)’, ‘order.setDiscount(order.getDiscount() + 20.0);’, 1);
5.2 从数据库加载并注册规则
创建一个新的服务类DynamicRuleService.java:
package com.example.ruleengine.service;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.core.RuleBuilder;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
@Service
public class DynamicRuleService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private RulesEngine rulesEngine;
private Rules dynamicRules = new Rules();
@PostConstruct // 应用启动时加载规则
public void loadRulesFromDB() {
String sql = “SELECT rule_name, rule_condition, rule_action, priority FROM business_rule WHERE enabled = true”;
List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(sql);
for (Map<String, Object> row : ruleList) {
String name = (String) row.get(“rule_name”);
String condition = (String) row.get(“rule_condition”);
String action = (String) row.get(“rule_action”);
int priority = (Integer) row.get(“priority”);
// 使用MVEL表达式引擎构建规则
Rule rule = new RuleBuilder()
.name(name)
.when(condition) // MVEL表达式字符串
.then(action) // MVEL表达式字符串
.priority(priority)
.build();
dynamicRules.register(rule);
}
}
public void fireDynamicRules(Facts facts) {
rulesEngine.fire(dynamicRules, facts);
}
}
注意:使用MVEL规则时,确保事实对象(如order)的属性在表达式上下文中可访问。你需要在applyRules方法中调用fireDynamicRules,并确保Order类有userLevel属性。
六、生产环境部署与监控要点
将规则引擎投入生产环境,需注意以下几点。
6.1 性能与线程安全
- 规则引擎实例:建议使用
@Scope(“prototype”)为每个请求或线程创建独立的引擎实例,避免状态共享问题。 - 规则缓存:动态规则从数据库加载后,应放入本地缓存(如Caffeine),设置合理的过期时间,避免频繁查询数据库。
6.2 规则版本管理与回滚
在business_rule表中增加字段:version(版本号)、publish_time(发布时间)。发布新规则时,插入一条新记录并更新版本号。在服务层,始终加载最新生效版本的规则。出现问题需回滚时,只需将旧版本规则的enabled设为true,新版本设为false即可。
6.3 日志与监控
在RuleEngineConfig中配置规则引擎监听器,记录每次规则触发的详细信息:
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
rulesEngine.registerRuleListener(new RuleListener() {
@Override
public void onSuccess(Rule rule, Facts facts) {
log.info(“规则 [{}] 执行成功, 事实: {}”, rule.getName(), facts);
}
});
将日志接入ELK(Elasticsearch, Logstash, Kibana)或类似监控系统,便于问题排查和规则效果分析。
至此,一个具备核心功能、支持动态配置、可直接用于生产环境的规则引擎已构建完成。你可以根据业务需求,定义更多的@Condition和@Action,或集成更复杂的Drools等引擎,其架构思想与此一脉相承。
版权保护: 本文由 741卡盟 原创,转载请保留链接: http://741ka.com/gamenews/23178.html
- 上一篇:天机泄露《YY仙战》公测版本亮相
- 下一篇:蝙蝠侠阿甘之城冷枪任务教程
