Drools中文网

基于java的功能强大的开源规则引擎

本站QQ群:
446150745

drools 学习笔记

大多数web和企业Java应用可以分成三个部分:一个和用户交互的前台, 一个和后台系统,例如数据库交互的服务层,以及他们中间的业务逻辑。 现在使用框架构建前台和后台系统已经成为普遍共识(例如, Struts, Cocoon,spring, hibernate, JDO, 和 Entity Beans), 但却没有一个标准的方法来构建业务逻辑。一些框架,例如 EJB 和 Spring 只在一个高层实现业务逻辑,但对于我们组织逻辑代码没有任何帮助,所以,为什么没有一个框架来替换冗繁,易错的if…then语句呢,这个框架应该和其它前台或后台框架一样,易于配置,具有可读性和重用性。下面我们将介绍Drools 规则引擎,这个来解决我们问题的框架。 
我们经常能见到噩梦般的业务逻辑代码: 
if ((user.isMemberOf(AdministratorGroup)&& user.isMemberOf(teleworkerGroup))|| user.isSuperUser(){ 
// more checks for specific cases 
    if((expenseRequest.code().equals(“B203”)||(expenseRequest.code().equals(“A903”)&&(totalExpenses<200)&&(bossSignOff> totalExpenses))&&(deptBudget.notExceeded)) { 
    //issue payments 
    } else if { 
    //check lots of other conditions 
    } 
} else { 
// even more business logic 
} 
当然会有一些优秀的程序员可以写出更漂亮些的代码,但那是相当费神的。而Drools等规则引擎 提供了一种很好的解决途径。 
先来看Drools的一个简单的例子: 
   应用:某公司要对某一次参与生产的员工计算工资。 
   工资=产量*基本工资*系数 
   系数与该员工的产品合格率有关: 合格率=1 系数=1;0.9<=合格率<1 系数=0.95 ;0.85<=合格率<9 系数=0.9;0.8<=合格率<0.85 系数=0.8;合格率<0.8 系数=0.6; 
   假设我们有这么一个类:

Java代码

  1.   public class Employee {   
  2. private String name;   
  3.   
  4. private int product;   
  5.   
  6. private float hgl;   
  7. …   
  8.    }  
[java] view plain copy

  1. public class Employee {  
  2.  private String name;  
  3.   
  4.  private int product;  
  5.   
  6.  private float hgl;  
  7.  …  
  8.    }  


   上面应用用Drools的drl 应该这样描述:  

Java代码

  1. rule “FirstGz”  
  2.        
  3.      when   
  4.          e:Employee(hgl==1);   
  5.      then   
  6.          System.out.println(e.getName()+“的工资:”+e.getProduct()*50*1);   
  7.            
  8. end   
  9.   
  10. rule “SecondGz”  
  11.      when   
  12.          e:Employee(hgl<1,hgl>=0.9);   
  13.      then   
  14.          System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.95);   
  15.          retract(e);   
  16.            
  17. end   
  18.   
  19. rule “3Gz”  
  20.      when   
  21.          e:Employee(hgl<0.9,hgl>=0.85);   
  22.      then   
  23.          System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.9);   
  24.          retract(e);   
  25.            
  26. end   
  27.   
  28. rule “4Gz”  
  29.      when   
  30.          e:Employee(hgl<0.85,hgl>=0.8);   
  31.      then   
  32.          System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.85);   
  33.          retract(e);   
  34.            
  35. end   
  36.   
  37. rule “5Gz”  
  38.      when   
  39.          e:Employee(hgl<0.8);   
  40.      then   
  41.          System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.6);   
  42.          retract(e);   
  43.            
  44. end   
[java] view plain copy

  1. rule “FirstGz”  
  2.    
  3.  when  
  4.   e:Employee(hgl==1);  
  5.  then   
  6.      System.out.println(e.getName()+“的工资:”+e.getProduct()*50*1);  
  7.     
  8. end  
  9.   
  10. rule “SecondGz”  
  11.  when  
  12.   e:Employee(hgl<1,hgl>=0.9);  
  13.  then   
  14.      System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.95);  
  15.      retract(e);  
  16.     
  17. end  
  18.   
  19. rule “3Gz”  
  20.  when  
  21.   e:Employee(hgl<0.9,hgl>=0.85);  
  22.  then   
  23.      System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.9);  
  24.      retract(e);  
  25.     
  26. end  
  27.   
  28. rule “4Gz”  
  29.  when  
  30.   e:Employee(hgl<0.85,hgl>=0.8);  
  31.  then   
  32.      System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.85);  
  33.      retract(e);  
  34.     
  35. end  
  36.   
  37. rule “5Gz”  
  38.  when  
  39.   e:Employee(hgl<0.8);  
  40.  then   
  41.      System.out.println(e.getName()+“的工资:”+e.getProduct()*50*0.6);  
  42.      retract(e);  
  43.     
  44. end  


   
这样就把业务逻辑和程序分开来了。如果要修改业务逻辑,那也是很容易的,只要修改Rule文件就可以了,而Rule文件是可以在一种类似XML的独立文件,可以很方便的替换修改。

 

Drools 是一个开源的规则引擎,目前有Jboss管理,最新版本为5.X。 
我们使用Drools就是为了让它处理数据与规则的关系,因此Drools要获得数据和获得规则,然后进行执行。因此Drools分为编制和运行时两个部分。 
编制是指产生rule的过程,Drools用DRL,或者XML来描述规则。 
编制的过程包括为规则建立DRL 或XML 文件,传入一个由Antlr 3 文法器定义的解析器中。解析器对文件中规则文法的正确性进行检查并为descr 建立一个中间结构,在AST 中的descr 代表规则的描述。AST 然后将descr 传入Package Builder中,由其进行打包。Package Builder 同时负责包括打包中用到的所有代码产生器和编译器。Package 对象是自包含并可配置的,它是一个包含规则的序列化的对象。 

RuleBase 是运行时组件,包含一个或多个Package。Package 在任何时候都可以向RuleBase中添加或删除。一个RuleBase 可以同时初始化多个Working Memory,在其间维护着一个弱引用,除非重新进行配置。Working Memory 包含许多子组件,如Working Memory Event Support(事件支持),Truth Maintenance System(真值维护系统), Agenda 和 Agenda Event Support(事件支持)。向Working Memory 中设置对象的工作可能要在建立了一个或多个激活的规则后才结束。Agenda 负有规划激活规则运行的责任。 

以上是Drools的总体架构,其主要有以下类实现: 
编制: 
XmlParser,DrlParser 分别用来解析XML描述的规则文件和DRL描述的规则文件。 
PackageBuilder 创建package实例。 
例如: 
PackageBuilder builder = new PackageBuilder(); 
builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( “package1.drl” ) ) ); 
builder.addPackageFromXml( new 
InputStreamReader( getClass().getResourceAsStream( “package2.xml” ) ) ); 

Package pkg = builder.getPackage(); 

运行时的类: 
RuleBase 使用RuleBaseFactory 实例化,默认情况下返回一个ReteOO 的RuleBase。Package通过使用addPackage 方法按顺序加入。你可以指定任何名称空间的Packages 或者同一名称的多个包加入RuleBase。 

RuleBase ruleBase = RuleBaseFactory.newRuleBase(); 
ruleBase.addPackage( pkg ); 

事实数据相关类: 
WorkingMemory 保存运行时事实数据的地方。 
由ruleBase产生:WorkingMemory wm= ruleBase.newStatefulSession(); 
加载事实数据: 
wm.insert(object ); 

insert方法返回一个FactHandle对象指向workingMemory中对象的引用。如果要对Object进行修改删除等操作都要通过FactHander对象来完成。 

在准备好Rule,和Fact后 就可以调用 WorkingMemory对象的 fireAllRules()方法执行规则引擎。 

Agenda上面提到过它负有规划激活规则运行的责任。 
它运行过程分两个阶段: 
1) WorkingMemory Actions : assert 新的 facts ,修改存在的 facts 和 retract facts 
都是 WorkingMemory Actions 。通过在应用程序中调用 fireAllRules() 方法,会使引擎 
转换到 Agenda Evaluatioin 阶段。 
2) Agenda Evaluation :尝试选择一条规则进行激发( fire )。如果规则没有找到就 
退出,否则它就尝试激发这条规则,然后转换到 WorkingMemory Actions 阶段,直到 Agenda 
中为空。 

Drools提供了一些监听器来获得规则引擎执行过程中发生的一些事件: 
WorkingMemoryEventListene,AgendEventListener和RuleFlowEventListener 

从名称来看我们也大概能知道他们分别的作用: 
WorkingMemoryEventListene是监听WorkingMemory中发生的一些时间,WorkingMemory发生的事件那就是Fact的插入,删除,修改。 
对应的借口为: 
objectInserted(ObjectInsertedEvent e); 
objectRetracted(ObjectRetractedEvent e); 
objectUpdated(ObjectUpdatedEvent e); 
AgendEventListener是舰艇运行过程中Agenda管理调配规则发生的一些事件: 
Action 在我理解应该是一个冲突就是上面提到过的 完全符合规则条件的,包含规则和数据的对象。 
activationCancelled action被取消,可能是因为在规则的执行过程中,某个对象被修改或者某个对象被删除引起。 
activationCreated 当有数据能匹配到规则,就能发生这个事件。 
afterActivationFired 在规则执行后触发这个事件 
agendaGroupPopped 规则组。。。 
agendaGroupPushed 
beforeActivationFired 在规则执行前触发这个事件 
Drools4.0 自带一种非XML 格式的规则语言。这种格式通过使用标点符号,使得语言非常的轻量化,并且通过DSL(域规则语言)支持自然语言的扩展,这使得你可以将该语言演化到与你需要解决的问题域更为相配。 

规则文件通常是以drl 扩展名结尾。在一个drl 文件中可以包含多个规则,函数等等。但是你也可以将规则分开到多个规则文件中(在这种情况下建议采用.rule 扩展名,但不是必需的),分散规则利于管理巨量规则的情况。DRL 是简单的text 文件格式。 
完整的DRL文件结构是: 
package package-name 
imports 
globals 
functions 
queries 
rules 

其中package是必须的。 
Imports的含义和Java里的imports含义相似。 
Globals表示全局的Fact但它并不进入匹配过程。 
Functions queries rules就是我们要写的业务逻辑了,我们用的最多的就是Rules。 
RULE的基本结构: 
rule “ruleName” 
when 
<LHS> 
Then 
        <RHS> 
end 
规则指定“when”作为一系列条件的集合(称为LHS),然后在“then”中指定一系列操作 
(称为RHS)。(有些类似if…then) 
不多介绍语法,介绍一下下面的例子: 
rule “Purchase notification” 
    salience 10 
when 
$c : Customer() 
$p : Purchase( customer == $c)     
then 
    System.out.println( “Customer ” + $c.name + ” just purchased ” + $p.product.name ); 
end 
第一行 Purchase notification是这个Rule的name,Rule name和Java的名称一样 在同一个包内不能重名。salience 10表示rule执行的优先级,当一个Fact进入WorkingMemory后可能有几个规则被触发,那你可以执行一个优先级来执行这些规则的执行顺序。 
When下的部分是LHS, $c : Customer()表示触发规则的对象必须是Customer类型。并创建了一个Customer对象的引用 $c,$c可以在这个rule内使用。$p : Purchase( customer == $c)表示存在一个Purchase对象并且该对象的customer属性为上面描述的customer对象。如果符合上面两个条件规则引擎会执行then部分。Then部分的语法由于基本可以理解为Java语法。


Warning: count(): Parameter must be an array or an object that implements Countable in /www/wwwroot/www.drools.org.cn/wp-includes/class-wp-comment-query.php on line 405

留下评论