学前
有这样一串代码,代表着积分策略业务,计算额外积分金额:
- 100 以下, 不加分;
- 100-500 加100分;
- 500-1000 加500分;
- 1000 以上 加1000分;
public class JavaScoreExample {
public static void main(String[] args) throws Exception {
List<Order> orderList = getInitData();
for (int i=0; i<orderList.size(); i++){
Order order = orderList.get(i);
if (order.getAmout() <= 100){
order.setScore(0);
addScore(order);
}else if(order.getAmout() > 100 && order.getAmout() <= 500){
order.setScore(100);
addScore(order);
}else if(order.getAmout() > 500 && order.getAmout() <= 1000){
order.setScore(500);
addScore(order);
}else{
order.setScore(1000);
addScore(order);
}
}
}
private static void addScore(Order o){
System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());
}
private static List<Order> getInitData() throws Exception {
List<Order> orderList = new ArrayList<Order>();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
{
Order order = new Order();
order.setAmout(80);
order.setBookingDate(df.parse("2015-07-01"));
User user = new User();
user.setLevel(1);
user.setName("Name1");
order.setUser(user);
orderList.add(order);
}
{
Order order = new Order();
order.setAmout(200);
order.setBookingDate(df.parse("2015-07-02"));
User user = new User();
user.setLevel(2);
user.setName("Name2");
order.setUser(user);
orderList.add(order);
}
return orderList;
}
}
综上,如果这时由于市场需求变化,又要调整规则时候,则又要进行业务层面的代码修改、部署,十分麻烦。
那该怎么办呢?
规则引擎
作用
我们可以把决策规则从应用程序中分离出来,将对系统提供很大的便利
优势
- 简化系统架构,优化应用
- 提高系统的可维护性和维护成本
- 减少编写“硬代码”业务规则的成本和风险
Drools
Drools是一个基于java的规则引擎,它是开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效。具有易于访问企业策略、易于调整以及易于管理的特点,作为开源业务规则引擎,符合业内标准,速度快、效率高。
项目搭建流程
以下项目基于Springboot搭建
项目结构
项目存放:image/drool.rar
pom.xml
<!--drools规则引擎-->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>7.6.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>7.6.0.Final</version>
</dependency>
配置文件
@Configuration
public class RuleEngineConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(RuleEngineConfig.class) ;
private static final String RULES_PATH = "droolRule/";
private final KieServices kieServices = KieServices.Factory.get();
@Bean
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
String path = null;
for (Resource file : files) {
path = RULES_PATH + file.getFilename();
LOGGER.info("path="+path);
kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
}
return kieFileSystem;
}
@Bean
public KieContainer kieContainer() throws IOException {
KieRepository kieRepository = kieServices.getRepository();
kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
kieBuilder.buildAll();
return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
}
@Bean
public KieBase kieBase() throws IOException {
return kieContainer().getKieBase();
}
@Bean
public KieSession kieSession() throws IOException {
return kieContainer().newKieSession();
}
@Bean
public KModuleBeanFactoryPostProcessor kiePostProcessor() {
return new KModuleBeanFactoryPostProcessor();
}
}
规则文件
语法说明
- 文件格式:可以 .drl、xml文件,也可以Java代码块硬编码
- package:规则文件中,package是必须定义的,必须放在规则文件第一行
- import:规则文件使用到的外部变量,可以是一个类,也可以是类中的可访问的静态方法
- rule:定义一个规则。paramcheck1规则名。规则通常包含三个部分:属性、条件、结果
规则说明
- salience 的值越大,越优先执行
- 规则流程:如果paramId不为null,参数标识是+号,执行添加规则,-号,执行移除规则操作
dialect "java"
rule "paramcheck1"
salience 99
when queryParam : QueryParam(paramId != null && paramSign.equals("+"))
resultParam : RuleResult()
then
final Logger LOGGER = LoggerFactory.getLogger("param-check-one 规则引擎") ;
LOGGER.info("参数:getParamId="+queryParam.getParamId()+";getParamSign="+queryParam.getParamSign());
RuleEngineServiceImpl ruleEngineService = new RuleEngineServiceImpl() ;
ruleEngineService.executeAddRule(queryParam);
resultParam.setPostCodeResult(true);
end
dialect "java"
rule "paramcheck2"
salience 88
when queryParam : QueryParam(paramId != null && paramSign.equals("-"))
resultParam : RuleResult()
then
final Logger LOGGER = LoggerFactory.getLogger("param-check-two 规则引擎") ;
LOGGER.info("参数:getParamId="+queryParam.getParamId()+";getParamSign="+queryParam.getParamSign());
RuleEngineServiceImpl ruleEngineService = new RuleEngineServiceImpl() ;
ruleEngineService.executeRemoveRule(queryParam);
resultParam.setPostCodeResult(true);
end
规则执行代码
@Service
public class RuleEngineServiceImpl implements RuleEngineService {
private static final Logger LOGGER = LoggerFactory.getLogger(RuleEngineServiceImpl.class) ;
@Override
public void executeAddRule(QueryParam param) {
LOGGER.info("参数数据:"+param.getParamId()+";"+param.getParamSign());
ParamInfo paramInfo = new ParamInfo() ;
paramInfo.setId(param.getParamId());
paramInfo.setParamSign(param.getParamSign());
paramInfo.setCreateTime(new Date());
paramInfo.setUpdateTime(new Date());
ParamInfoService paramInfoService = (ParamInfoService)SpringContextUtil.getBean("paramInfoService") ;
paramInfoService.insertParam(paramInfo);
}
@Override
public void executeRemoveRule(QueryParam param) {
LOGGER.info("参数数据:"+param.getParamId()+";"+param.getParamSign());
ParamInfoService paramInfoService = (ParamInfoService)SpringContextUtil.getBean("paramInfoService") ;
ParamInfo paramInfo = paramInfoService.selectById(param.getParamId());
if (paramInfo != null){
paramInfoService.removeById(param.getParamId()) ;
}
}
}
规则调用接口
@RestController
@RequestMapping("/rule")
public class RuleController {
@Resource
private KieSession kieSession;
@Resource
private RuleEngineService ruleEngineService ;
@RequestMapping("/param")
public void param (){
QueryParam queryParam1 = new QueryParam() ;
queryParam1.setParamId("1");
queryParam1.setParamSign("+");
QueryParam queryParam2 = new QueryParam() ;
queryParam2.setParamId("2");
queryParam2.setParamSign("-");
// 入参
kieSession.insert(queryParam1) ;
kieSession.insert(queryParam2) ;
kieSession.insert(this.ruleEngineService) ;
// 返参
RuleResult resultParam = new RuleResult() ;
kieSession.insert(resultParam) ;
kieSession.fireAllRules() ;
}
}
由于水平有限,本博客难免有不足,恳请各位大佬不吝赐教!