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.    }  
public class Employee {
 private String name;

 private int product;

 private float hgl;
 ...
   }


   上面应用用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   
rule "FirstGz"
 
 when
  e:Employee(hgl==1);
 then 
     System.out.println(e.getName()+"的工资:"+e.getProduct()*50*1);
  
end

rule "SecondGz"
 when
  e:Employee(hgl<1,hgl>=0.9);
 then 
     System.out.println(e.getName()+"的工资:"+e.getProduct()*50*0.95);
     retract(e);
  
end

rule "3Gz"
 when
  e:Employee(hgl<0.9,hgl>=0.85);
 then 
     System.out.println(e.getName()+"的工资:"+e.getProduct()*50*0.9);
     retract(e);
  
end

rule "4Gz"
 when
  e:Employee(hgl<0.85,hgl>=0.8);
 then 
     System.out.println(e.getName()+"的工资:"+e.getProduct()*50*0.85);
     retract(e);
  
end

rule "5Gz"
 when
  e:Employee(hgl<0.8);
 then 
     System.out.println(e.getName()+"的工资:"+e.getProduct()*50*0.6);
     retract(e);
  
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语法。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值