InfoQ发布了一个关于规则引擎的介绍Real-World Rule Engines,ONJava上也有两篇文章:

Give Your Business Logic a Framework with Drools ​​http://www.onjava.com/lpt/a/6093​

Using Drools in Your Enterprise Java Application  ​​http://www.onjava.com/lpt/a/6160​

下面总结一下其中的精华:

大多数web和企业Java应用可以分成三个部分:一个和用户交互的前台, 一个和后台系统,例如数据库交互的服务层,以及他们中间的业务逻辑。 现在使用框架构建前台和后台系统已经成为普遍共识(例如, Struts, Cocoon, Spring, Hibernate, JDO, 和 Entity Beans), 但却没有一个标准的方法来构建业务逻辑。一些框架,例如 EJB 和 Spring 只在一个高层实现业务逻辑,但对于我们组织逻辑代码没有任何帮助,所以,为什么没有一个框架来替换冗繁,易错的if...then语句呢,这个框架应该和其它前台或后台框架一样,易于配置,具有可读性和重用性。下面我们将介绍Drools 规则引擎,这个来解决我们问题的框架。

下面是一个典型的Java业务逻辑的代码

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

}


这是大多数程序员写业务逻辑的方法,但是有以下的问题:

  • 如果用户有另一个选项,例如("C987") ,那么需要修改上面的代码,当代码很长的时候,修改代码是难于维护的
  • 我们如何保证代码的正确性,这个代码只有程序员能够看到,真正的使用者,业务人员无法看到这个代码
  • 很多应用程序有相同的业务逻辑,如果某个业务改变了,如何保证其他业务逻辑的一致性
  • 业务逻辑能否不合java语言绑定?
  • 业务逻辑能否用其他的脚本语言。

Java下的规则引擎标准就是JSR94,它的实现主要有​​Jess​​ ​​Jena​​ ​​Drools​

Drools中,一个典型的业务逻辑的配置,如下

<?xml version="1.0"?>

<rule-set name="BusinessRulesSample"

  xmlns="http://drools.org/rules"

  xmlns:java="http://drools.org/semantics/java"

  xmlns:xs

    ="http://www.w3.org/2001/XMLSchema-instance"

  xs:schemaLocation

    ="http://drools.org/rules rules.xsd

  http://drools.org/semantics/java java.xsd">

  <!-- Import the Java Objects that we refer

                          to in our rules -->       

  <java:import>

    java.lang.Object

  </java:import>

  <java:import>

    java.lang.String

  </java:import>

  <java:import>

    net.firstpartners.rp.StockOffer

  </java:import>

  <!-- A Java (Utility) function we reference

    in our rules--> 

  <java:functions>

    public void printStock(

      net.firstpartners.rp.StockOffer stock)

        {

        System.out.println("Name:"

          +stock.getStockName()

          +" Price: "+stock.getStockPrice()    

          +" BUY:"

          +stock.getRecommendPurchase());

        }

  </java:functions>

<rule-set>

  <!-- Ensure stock price is not too high-->     

  <rule name="Stock Price Low Enough">

    <!-- Params to pass to business rule -->

    <parameter identifier="stockOffer">

      <class>StockOffer</class>

    </parameter>

    <!-- Conditions or 'Left Hand Side'

        (LHS) that must be met for

         business rule to fire -->

    <!-- note markup -->

    <java:condition>

      stockOffer.getRecommendPurchase() == null

    </java:condition>

    <java:condition>

      stockOffer.getStockPrice() < 100

    </java:condition>

    <!-- What happens when the business

                      rule is activated -->

    <java:consequence>

        stockOffer.setRecommendPurchase(

                              StockOffer.YES); 

          printStock(stockOffer);

    </java:consequence>

  </rule>

</rule-set>

一条规则就是rule-set中的rule,如果有很多规则,就要写很多的rule。

上面规则的意思是判断股票价格是否小于100,如果100这个标准改变了,那么只要修改这个规则文件,而不用去修改源代码了