在路上

          路上有驚慌,路上有理想

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

          Drools 是用 Java 語言編寫的開放源碼規(guī)則引擎。Drools 允許使用聲明方式表達業(yè)務邏輯。可以使用非 XML 的本地語言編寫規(guī)則(這點很重要,本人之前曾用過自己公司的一套業(yè)務規(guī)則組件,無論是編寫還是調試都很麻煩),從而便于學習和理解。并且,還可以將 Java 代碼直接嵌入到規(guī)則文件中,使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

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

          接下來
          語法說明:


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

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




          <name> 即rule的名字標識

          <attribute>:

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

          其他屬性的解釋請見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:業(yè)務規(guī)則的地方,略。

          2.用法

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


          如上圖,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文件的所有規(guī)則的集合)
          executeRules方法定義了如何使用規(guī)則文件中定義的那些內容,用RuleBase構建一個WorkingMemory對象,再執(zhí)行fireAllRules()方法。
          WorkingMemory 代表了與rulebase鏈接的session會話,也可以看作是工作內存空間。如果你要向內存中插入一個對象可以調用insert()方法,同理,更新一個對象使用update()方法。WorkingMemory還有一個setGlobal()方法,用來設置規(guī)則內可以引用的對象(相當于規(guī)則的全局變量)。

          3.小技巧

            可以一次把所有的rule文件都載入內存中存放,這樣就不用每次執(zhí)行都讀取文件。
            如果規(guī)則文件被修改,也可以用過一個方法來判斷是否需要重新載入rule文件
            比如:根據(jù)文件的最后修改時間,與內存中對應對象的時間做比較
          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
          主站蜘蛛池模板: 张家口市| 五寨县| 綦江县| 台湾省| 田东县| 乐至县| 璧山县| 阳山县| 惠水县| 漯河市| 如东县| 盱眙县| 黄骅市| 浦北县| 邳州市| 鄂伦春自治旗| 昌都县| 宜丰县| 固安县| 长垣县| 行唐县| 满洲里市| 延安市| 宁夏| 梧州市| 广灵县| 句容市| 上蔡县| 遵化市| 宽甸| 多伦县| 怀仁县| 长宁区| 亳州市| 万载县| 桓仁| 竹山县| 泰兴市| 甘谷县| 宜宾县| 永修县|