按照学习drools的系列文章的习惯,一般是理论+实践(示例),在Java规则引擎学习-drools(五),转了一篇基于Spring的规则引擎的集成的文章,本文将讨论怎么使用Spring集成drools。这里我想使用Springside中的对drools的集成做一个介绍:
1. BaseLoader.java
此类是是一个接口,其实现类将从数据库或drl文件中读取RuleBase,代码如下:
public interface BaseLoader {
public RuleBase buildRuleBase(String RulesetName, Date date) throws Exception;
}
2. FileRuleBaseLoader.java
此类是BaseLoader的实现类,负责从drl文件中读取并组装成Drools RuleBase。
代码如下:
public class FileRuleBaseLoader implements BaseLoader {
private Map ruleSetFileMap;
public void setRuleSetFileMap(Map ruleSetFileMap) {
this.ruleSetFileMap = ruleSetFileMap;
}
public RuleBase buildRuleBase(String ruleSetName, Date date) throws Exception {
String filePath = (String) ruleSetFileMap.get(ruleSetName);
if (filePath == null)
throw new Exception("No RuleSet found by Name:" + ruleSetName);
InputStream is = this.getClass().getResourceAsStream(filePath);
if (is == null)
throw new Exception("No RuleSet found by Name:" + ruleSetName);
return RuleBaseLoader.loadFromInputStream(is);
}
}
3. RuleService.java
public interface RuleService {
/**
* 执行规则
*
* @param ruleSetName 执行的规则集名
* @param facts 参与规则运算的事实列表
* @param date 运算日期,用于选择有效期内的规则
*/
public List executeRules(String ruleSetName, List facts, Date date) throws Exception;
/**
* 参见 excueteRules(String ruleSetName, List facts, Date date)
*/
public List executeRules(String ruleSetName, Object fact, Date date) throws Exception;
}
4. DroolsTemplate.java
public class DroolsTemplate implements RuleService {
private BaseLoader ruleBaseLoader;
private Cache ruleCache;
/**
* 执行规则,见接口定义
*/
public List executeRules(String ruleSetName, Object fact, Date date) throws Exception {
List facts = new ArrayList();
facts.add(fact);
return executeRules(ruleSetName, facts, date);
}
/**
* 执行规则,见接口定义
*/
public List executeRules(String ruleSetName, List facts, Date date) throws Exception {
RuleBase rb = loadRuleBase(ruleSetName, date);
WorkingMemory session = rb.newWorkingMemory();
for (Iterator objectIter = facts.iterator(); objectIter.hasNext();) {
session.assertObject(objectIter.next());
}
session.fireAllRules();
return session.getObjects();
}
/**
* 会先尝试从Cache中获取,如果为空则从数据库或drl文件中获取规则并重新编译RuleSet
*/
private RuleBase loadRuleBase(String ruleSetName, Date date) throws Exception {
RuleBase ruleBase = (RuleBase) EhCacheUtil.getCache(ruleCache, ruleSetName + date);
if (ruleBase == null) {
ruleBase = ruleBaseLoader.buildRuleBase(ruleSetName, date);
EhCacheUtil.setCache(ruleCache, ruleSetName + date, ruleBase);
}
return ruleBase;
}
public void setRuleBaseLoader(BaseLoader ruleBaseLoader) {
this.ruleBaseLoader = ruleBaseLoader;
}
public void setRuleCache(Cache ruleCache) {
this.ruleCache = ruleCache;
}
}
5. ApplicationContext-rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<!-- Drools Template -->
<bean id="ruleService" class="org.springside.rule.DroolsTemplate">
<property name="ruleBaseLoader" ref="fileRuleBaseLoader"/>
</bean>
<bean id="fileRuleBaseLoader" class="org.springside.rule.FileRuleBaseLoader">
<property name="ruleSetFileMap">
<map>
<entry key="OrderPricing" value="drl/OrderPricing.xml"/>
</map>
</property>
</bean>
<bean id="ruleCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheName" value="ruleCache"/>
</bean>
</beans>
6. OrderPricing.xml
<?xml version="1.0"?>
<rule-set name="OrderPricing"
xmlns="http://drools.org/rules"
xmlns:groovy="http://drools.org/semantics/groovy"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://drools.org/rules rules.xsd
http://drools.org/semantics/groovy groovy.xsd">
<rule name="discount">
<parameter identifier="order">
<class>org.springside.bookstore.domain.Order</class>
</parameter>
<groovy:condition>order.getTotalPrice() >=100</groovy:condition>
<groovy:consequence>
Double price = order.getTotalPrice() *0.9d;
order.setDiscountPrice(price);
order.addApplyRule(drools.getRuleName());
</groovy:consequence>
</rule>
</rule-set>
7. 需要说明的是:上述代码采用了Ehcache来缓存rulebase。具体细节见上面代码。