在路上

          路上有驚慌,路上有理想

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            28 Posts :: 1 Stories :: 10 Comments :: 0 Trackbacks
          對于做軟件的人來說,唯一不變的就是變化。此為行業真理。而對于復雜業務系統的邏輯組件的定義不得不多考慮一下業務的可擴展性,來應對客戶的變化。選擇Rule Engine是一個不錯的方案。

          Drools 是用 Java 語言編寫的開放源碼規則引擎。Drools 允許使用聲明方式表達業務邏輯。可以使用非 XML 的本地語言編寫規則(這點很重要,本人之前曾用過自己公司的一套業務規則組件,無論是編寫還是調試都很麻煩),從而便于學習和理解。并且,還可以將 Java 代碼直接嵌入到規則文件中,使Drools 更加吸引人。簡單的概括,就是簡單使用,易于理解。而且它是免費的。

          1.rule文件:
          rule "rule name"  
              no-loop
              when
                customer : Customer( state == CustomerState.UNCENSORED )     
              then
                  customer.setState(CustomerState.AUDITING);
                  CustomerTask task=new CustomerTask();
                  Post law=userService.getPostByPostCode(Constants.PostCode.ROOT_LAW);
                  task.setAuditorPost(law);
                  task.setEntityState(CustomerState.AUDITING);
                  task.setEntityId(customer.getId());
                  task.setEntityCode(String.valueOf(customer.getId()));
                  task.setEntityType(Customer.class.getSimpleName());
                  task.setTitle(customer.getName()+" test");
                  taskService.assignmentTask(task);
                  logger.info("CustomerTask Submit auditorTitle:" + task.getAuditorTitle());
          end

          這里面有個狀態的條件判斷state == CustomerState.UNCENSORED ,then 關鍵字后面的便是符合條件的處理邏輯,只要是java程度都可以看懂,比xml類的rule文件好懂了許多。

          接下來
          語法說明:


          文件頭部分:
          package drools.java.demo;定義包名,等同于命名空間
          import drools.java.demo.Machine;導入java類
          global java.util.List myGlobalList;此關鍵字讓規則引擎知道,myGlobalList對象應該可以從規則中訪問.
          function:
          類似于公用方法的抽象,如下定義后,各個同一文件下的rule都可以使用
          function void setTestsDueTime(Machine machine, int numberOfDays) {
              setDueTime(machine, Calendar.DATE, numberOfDays);
          }
          rule:定義了一個規則

          rule "<name>"
          <attribute>*
          when
          <conditional element>*
          then
          <action>*
          end




          <name> 即rule的名字標識

          <attribute>:

          常用的屬性:
          no-loop :true 條件結果更改后,修改此條件且定義為no-loop:true的規則不會再重新執行。
          lock-on-active:true 可以看作是no-loop的加強版,當條件結果更改后,不但修改此條件的規則不會重新執行,文件中的任何規則(其 active-lock 屬性被設為 true)不會重新執行。
          salience:100 使用它可以讓規則執行引擎知道應該啟動規則的結果語句的順序。具有最高顯著值的規則的結果語句首先執行;具有第二高顯著值的規則的結果語句第二執行,依此類推。當您需要讓規則按預定義順序啟動時,這一點非常重要。

          其他屬性的解釋請見http://downloads.jboss.com/drools/docs/5.1.1.34858.FINAL/drools-expert/html_single/index.html#d0e2607

          when:填寫條件的地方,比如:
          Cheese( type == "stilton", price < 10, age == "mature" )或

          Cheese( type == "stilton" && price < 10, age == "mature" )

          then:業務規則的地方,略。

          2.用法

          規則文件定義好后,就該是怎么使用它了


          如上圖,file rule定義好后,就該是如何使用它了。最重要的兩個類RuleBase和WorkingMemory

          下面是一個example:
          public class RulesEngine {
              private RuleBase rules;
              private boolean debug = false;
              public RulesEngine(String rulesFile) throws RulesEngineException {
                  super();
                  try {
                      // Read in the rules source file
                      Reader source = new InputStreamReader(RulesEngine.class
                              .getResourceAsStream("../../rules/" + rulesFile));

                      // Use package builder to build up a rule package
                      PackageBuilder builder = new PackageBuilder();

                      // This will parse and compile in one step
                      builder.addPackageFromDrl(source);

                      // Get the compiled package
                      Package pkg = builder.getPackage();

                      // Add the package to a rulebase (deploy the rule package).
                      rules = RuleBaseFactory.newRuleBase();
                      rules.addPackage(pkg);

                  } catch (Exception e) {
                      throw new RulesEngineException(
                              "Could not load/compile rules file: " + rulesFile, e);
                  }
              }
              public RulesEngine(String rulesFile, boolean debug)
                      throws RulesEngineException {
                  this(rulesFile);
                  this.debug = debug;
              }
              public void executeRules(WorkingEnvironmentCallback callback) {
                  WorkingMemory workingMemory = rules.newStatefulSession();
                  if (debug) {
                      workingMemory
                              .addEventListener(new DebugWorkingMemoryEventListener());
                  }
                  callback.initEnvironment(workingMemory);
                  workingMemory.fireAllRules();
              }
          }
          RulesEngine構造方法演示了如何去讀入一個rule文件,并構建了一個RuleBase對象(RuleBase 是一個包含了rule文件的所有規則的集合)
          executeRules方法定義了如何使用規則文件中定義的那些內容,用RuleBase構建一個WorkingMemory對象,再執行fireAllRules()方法。
          WorkingMemory 代表了與rulebase鏈接的session會話,也可以看作是工作內存空間。如果你要向內存中插入一個對象可以調用insert()方法,同理,更新一個對象使用update()方法。WorkingMemory還有一個setGlobal()方法,用來設置規則內可以引用的對象(相當于規則的全局變量)。

          3.小技巧

            可以一次把所有的rule文件都載入內存中存放,這樣就不用每次執行都讀取文件。
            如果規則文件被修改,也可以用過一個方法來判斷是否需要重新載入rule文件
            比如:根據文件的最后修改時間,與內存中對應對象的時間做比較
          public boolean hasChange(List<RuleFile> ruleFileList){
                  for(RuleFile ruleFile:ruleFileList){
                      if(!ruleFile.getLastModifyTime().equals(ruleFileMap.get(ruleFile.getFileName()).getLastModifyTime())){
                          return true;
                      }
                  }
                  return false;
              }

          注:具體的helloWorld 請見http://www.ibm.com/developerworks/cn/java/j-drools/#listing12,比我說得好多了。
          posted on 2010-09-25 17:48 阮步兵 閱讀(5256) 評論(0)  編輯  收藏 所屬分類: OpenSource
          主站蜘蛛池模板: 周宁县| 青岛市| 自治县| 樟树市| 灵璧县| 常宁市| 灵川县| 呈贡县| 利川市| 长垣县| 青浦区| 阿克陶县| 本溪| 沾益县| 凤台县| 鞍山市| 八宿县| 邹城市| 武强县| 东莞市| 浑源县| 公安县| 库尔勒市| 宁波市| 阿图什市| 沛县| 阳山县| 页游| 金山区| 饶平县| 曲麻莱县| 临朐县| 阳山县| 汉寿县| 泾源县| 永川市| 陈巴尔虎旗| 洛宁县| 松原市| 友谊县| 乌拉特前旗|