??xml version="1.0" encoding="utf-8" standalone="yes"?>国产AV无码专区亚洲AV毛网站,在线综合亚洲中文精品,欧美亚洲国产SUVhttp://m.tkk7.com/sharkafeng/category/13282.htmlFocus on Eclipse Tools.zh-cnWed, 28 Feb 2007 20:24:47 GMTWed, 28 Feb 2007 20:24:47 GMT60在你的企业java应用中用Drools(?http://m.tkk7.com/sharkafeng/articles/59454.htmlThe Spark of ThinkingThe Spark of ThinkingFri, 21 Jul 2006 08:59:00 GMThttp://m.tkk7.com/sharkafeng/articles/59454.htmlhttp://m.tkk7.com/sharkafeng/comments/59454.htmlhttp://m.tkk7.com/sharkafeng/articles/59454.html#Feedback0http://m.tkk7.com/sharkafeng/comments/commentRss/59454.htmlhttp://m.tkk7.com/sharkafeng/services/trackbacks/59454.htmlhttp://www.onjava.com/pub/a/onjava/2005/08/24/drools.html
中文地址:
http://www.matrix.org.cn/resource/article/43/43782_Drools.html
关键词: Drools J2ee


什么是Drools
(译者增加:什么是Drools, 摘自drools.org)
Drools 是一个基于Charles Forgy's的Rete法的,专ؓJava语言所设计的规则引擎。Rete法应用于面向对象的接口Z商业对象的商业规则的表达更ؓ自然。Drools是用Java写的Q但能同时运行在Java?Net上?br />
Drools
Drools 被设计ؓ可插入式的语a实现。目前规则能用Java, Python和Groovy实现。更为重要的是,Drools提供了声明式E序设计(Declarative Programming),q且使用域描q语a(Domain Specific Languages (DSL))Q专Z的问题域定义了某U模式的Xml, 它已l够灵zd可以用来描述你的问题域。DSLs包含的XML元素(Element)和属?Attribute)代表了问题域中各U要素?br />
(原文开?
q段旉企业UJava直能让你睡着。有多少J2EE-EJB应用E序只是从网|取数据ƈ把它们存入到数据库中?但开发者真正应该开发和l护的却是他们应用程序中复杂的商业逻辑。这个问题不仅仅适用于将要新应用Q而且渐渐圎ͼ也适用于那些长期运行的商业核心应用Q它们的内部逻辑也需要经常改变,而且往往要求在一个非常短的时间内?br />
在以前的文章中,“用Drools让你的商业逻辑使用框架?我介l了Drools框架Q展CZ它如何用来组l复杂的商业逻辑。Drool用一l简单的Q众所周知的事物替换了许多~杂的if…then表达式。如果你l历q和商业客户的会议,qؓ他们提出的想要实现的东西的复杂程度搞得头痛,或许你应该考虑一下像Droolsq样的规则引擎了。这文章将向你展示如何在企业Java应用中用Drools.

一路到底的框架

大多数开发者都有自己喜q框架。无特定序Q它们包括表现层框架QStruts, JSF, Cocoon和SpringQ?持久化框ӞJDO, Hibernate, Cayenne and Entity BeansQ以及结构框?EJB, 又是Spring, Pico和Excalibur), q有其它很多。每U框枉各有所长,l开发者提供子许多“即开即用”的功能。用框架来部v应用意味着你避免了许多让h厌烦的细节,让你集中注意力到关键之处?br />到目前ؓ_在框架所能做的事中仍然有一个缺口,那就是商业逻辑没有框架。像EJB和Springq样的工兯好,但它们却几乎没有提及怎么l织你的那些if …then语句。把Drools加到你的开发工L中意味着现在你可以“一路到底”的使用框架来构Z的应用程序。图1昄了这L一个应?br />
image
?. 用于Java应用的框?br />
q篇文章基于我们已l了解的Drools框架的功能,q些功能可以让我们构L一个应用。]

我什么时候应该用规则引擎?
“如果你有一把锤子,那所有的东西都看h都像钉子”,q句话在软g工程领域几乎成了陈词滥调了。虽然规则引擎能解决我们的许多问题,但确实值得认真考虑一下规则引擎对我们的企业Java应用是否合适。需要问的问题有Q?br />
?我的应用E序有多复杂?对于那些只是把数据从数据库中传入传出Qƈ不做更多事情的应用程序,最好不要用规则引擎。但是,当在Java中有一定量的商业逻辑处理的话Q可以考虑Drools的用。这是因为很多应用随着旉的推U越来越复杂Q而Drools可以让你L应对q一切?br />
?我的应用的生命周期有多久Q?/b>q个问题的正答案往往是“o人惊讶的镎쀝――还记得那些认ؓ他们的程序不会苟zd2000q的大型机的E序员吗Q用规则引擎将会在中长期得到好处。像q篇文章所展示的那P甚至原型都能从Drools与灵zL法的l合中获益,让“原型系l”{化成生pȝ?br />
?我的应用需要改变吗Q?/b>唯一能确定的是你的需求将会改变,无论是在开发过E中或是在开发完成以后。Drools使用一个或多个单易配的XML文g帮你来应对这一切?br />
那么性能呢?
如果你正在写一个企业应用Q很有可能它会扩展到成百Q如果不是成千)的用戗你已经知道现有的Java和J2EE应用能做到这一点,但一个用了Drools的应用对q一压力的表现如何?{案是:“o人吃惊的好”。大多数开发者只是因Z愎쀜失控”而依赖于他h的代码(比如Q某U框ӞQ想惌个:Drools不仅可以让你的应用和“传l”的~程Ҏ(gu)一样快Q甚臛_以更?看下面:

?避免p糕的代?/b>QDrools引导开发者去做“正的事”。你可以定你正在写的代码是好的Q但你的开发伙伴呢Q你可以同样q样说吗Q用框架可以让你更L地写出更快,更好的代码?br />
?优化q的框架Q你有多次看见商业逻辑重复C数据库中提取相同的信息,从而降低了整个应用的速度Q如果正用的话,Drools不仅仅能够记住信息,而且q能C以往使用该信息进行测试的l果Q从而大q提升应用的速度?br />
?Rete法Q很多次我们q不是真正需要用“if”条件。被Drools实现的Rete法Q可以用一个优化的Ҏ(gu)替换掉所有的“if…then”表辑ּ。需要重Ҏ(gu)及的是:Rete法在用更多的内存来降低运行时延迟斚w作了折衷。当然这在现代的应用服务器中q不是一个问题,我们也ƈ不推荐你在移动手Z使用Drools!

我们到哪里了Q?/span>

在我们上一文章中Q我们写了一个基于Drools引擎的简单的股票交易E序。我们实C不同的商业规则,展示了我们可以如何迅速地改变规则去适应商业需求,q且JUnit试l了我们高度自信可以认pȝ实是像我们设想的那栯作的。但是这个应用几乎没有用户介面,而且用硬~码代替了数据库。ؓ了把我们的程序提升到企业U的水^Q我们需要增加两个主要的东西?br />
?某种用户介面Q最理想的是Z标准的Web表现层的框架?br />?一个数据存取对?DAO)让Drools与数据库Q或其它后端Q交互?br />
从现有表现框架中实现规则引擎

大多C业Java应用是通过Web介面q行交互的,其中最被广泛用的Web表现层框架是Apache的Struts。理想的l果是:我们写的应用可以从表现层知道它下面的应用?而不是通过相反的方向。它的好处在于不仅仅可以使我们将来变换其它的表现层(比如Ajax或web service界面Q,而且意味着CZ代码可以非常Ҏ(gu)地应用于其它像Spring的框架?br />
下面的代码片断演CZ始何从Web表现层调用商业逻辑Q通过规则引擎Q,q根据返回结果显CZ同的面。这一例子中,我们使用了一个Struts行ؓQ但其代码是和用其它表现层框架甚至一个Servlet或一个Jsp面是很cM的。这个片断用了struts-config.xml配置文gQJSP面来上?昄数据Qƈ且生成WAR文g来进行布|Ӏ片断展CZ怎样把规则引擎和web框架集成使用?br />
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import BusinessLayer;
/**
* Sample Struts action with Pseudocode
* 使用伪代码的Struts行ؓCZ
*/
public class SampleStrutsAction extends Action{
      
  /**
   * Standard Struts doPerfom method
   * 标准的Struts doPerformҎ(gu)
   */
  public ActionForward doPerform(
                ActionMapping mapping,
                    ActionForm form,
                    HttpServletRequest request,
                    HttpServletResponse response)
        throws InvalidEntryPointException {
//Local Variables
//本地变量
    StockOffer userOffer =null;
        
//Get any previous values from the session
//从session取得以前的数?br />    userOffer=(StockOffer)request.getSession()
           .getAttribute("PREVIOUS_STOCK_OFFER");
                
//create this object if it is null
//如ؓnull则创建新对象
    if (null==userOffer){
      userOffer = new StockOffer();
    }
//Update with the incoming values
//用上送的数据更新
//These values match those on the form      
//q些数据是与form中的数据相对应的
    userOffer.setStockName(request.
                getParameterValue("STOCK_NAME"));
    userOffer.setStockPrice(request
               .getParameterValue("STOCK_PRICE"));
    userOffer.setStockQuantity(request
               .getParameterValue("STOCK_QTY"));
                                
//Reset the output value
//重置输出数据
    userOffer.setRecommendPurchase(null);
//Call the Business Layer
//调用商业?br />    BusinessLayer
              .evaluateStockPurchase(userOffer);        
                
//Forward to the appropriate page
//转向合适的面
    if ("YES".equals(
      testOffer.getRecommendPurchase()){
        return mapping.findForward("YES_WEB_PAGE");
    }
//otherwise default to the no page
//否则指向无此面
          return mapping.findForward("NO_WEB_PAGE");
  }
}


q个例子包含了几个东ѝ经常,我们需要的数据是用户通过好几个网传来的Q因此在q一例子中展CZ通过session中的StockOffer对象来保存过M来的数据?br />
下一步,如果用户改变了一些|我们更新StockOffer对象。然后我们重|了rcommendPurchase标志用以在调用商业逻辑层之前清除以前的l果。最后我们用商业逻辑层的q回来决定让用户转向哪一面?br />
在这一例子中,需要注意我们将商业逻辑Q买或不C支股)与表现层逻辑Q决定{向哪一面Q分d来。这我们可以在不同的应用中重用我们的商业规则。另外,看一下状态信息(用户已经告知我们的东西)是存储在Session中的StockOffer对象中的Qƈ没有在商业层中。这样就保证了商业层的无状态性,q将使整个应用更h展性和性能?br />
集成规则引擎与数据库?/span>

到目前ؓ止,我们的应用已l有一个web表现层和一个商业层的规则引擎,但还没有Ҏ(gu)与数据库q行交互。这一节的例子展C如何实现。我们的例子是基于数据访问对象(DAOQ模式的Q它把所有与数据库(或后端数据源Q交互的代码包装在了一个可插入Q可配置的类中。同LQ这一例子一样适用于其它持久性框 Ӟ比如Hibernate和Cayenne?br />关于如何l织数据导有几个要点Q?br />
?应该只有商业层与数据层交互。如果表现层Q前端)需要一些数据,它首先应通过商业层。这我们的代码更Ҏ(gu)l织和阅诅R?br />?可能地Q我们应让我们的数据层无状态-我们应该在其它的地方存放客户端数据(比如Qweb前端的sessionQ就像前面的例子Q。这不同于我们可以在q一层做的数据缓存。两者的区别在于状态信息经常是用户定义的,而我们在数据层缓存的数据应该是整个应用共享的。这L层次提升了性能?br />?我们应该让商业逻辑军_数据是否需要――如不需要,提取数据的调用就不应该执行?br />
Z实现我们单的数据讉K对象Q我们创Z个新对象QStockNameDao, DaoImplementation,?DaoFactory

StockNameDao是一个定义了两个Ҏ(gu)的接口:getStockName()q回一个我们可以处理的股票名称的列?isOnStockList()查一个给定的股票是否在处理列表中。我们的商业层在需要这些信息时会调用这些方法?br />
DaoImplementation是StockNameDao的一个实现。这里的数据是硬~码的,但我们可以通过查询数据库或通过像Bloombergq样的web service提取信息?br />
DaoFactory我们用来生成合适的StockNameDao实例。不直接创徏对象而用这一骤的好处在于,它充许我们在q行时刻军_使用哪一个DAO实现Q这是像Springq样的框架特别擅长的Q?一个factoryQ工厂)可以q回多种cd的DAO(比如QStockNameDao, StockPriceDao, StockHistoryDao),q意味着我们可以通过我们的DaoFactory,让规则自己决定需要什么数据和DAO.

q是StockNameDao接口Q?br />
/**
* Defines a Data Access Object - a non data
* source specific way of obtaining data.
* 定义一个数据存取对象-一U非数据源获取数据的Ҏ(gu)
*/
public interface StockNameDao {
  /**
   * Get a list of stock names for the application
   * @return String[] array of stock names
   * 得到一个股名字的列表
   * q回股票名称的String[]数组
   */
  public String [] getStockNames();
        
  /**
   * Check if our stock is on the list
   * 查股是否在列表?br />   * @param stockName
   * @return
   */
  public boolean isOnStockList(String stockName);
}
And here's the DaoImplementation:
q是DaoImplementation:

/**
* Concrete Definition of a Data Access Object
* 数据存取对象的具体定?br /> */
public class DaoImplementation
                        implements StockNameDao {
  /**
   * Constructor with package level access only
   * to encourage use of factory method
   * q里的构造器只是让你使用工厂(factory)Ҏ(gu)
   */
  DaoImplementation(){}
  /**
   * Get a list of stock names for the app.
   * This is a hard coded sample
   * normally we would get this from
   * a database or other datasource.
   * 得到一个股名字的列表Q这只是一个硬~码的例子,一般来
  * 说我们应该从数据库或其它数据源取得数?br />   * @return String[] array of stock names
   */
  public String[] getStockNames() {
    String[] stockNames=
      {"XYZ","ABC","MEGACORP","SOMEOTHERCOMPANY"};
  
    return stockNames;
  }
        
  /**
   * Check if our stock is on the list
   * 查我们的股票是否在列表中
   * @param stockName
   * @return true / false as appropriate
   */
  public boolean isOnStockList(String stockName){
                
//Get our list of stocks  
//获取股票列表          
    String stockList[] = getStockNames();
                
    //Loop and see if our stock is on it
// done this way for clarity . not speed!
//循环看股是否存在,q样做是Z清晰不是速度!
    for (int a=0; a<stockList.length;a++){
        if(stockList[a].equals(stockName)){
          return true;
        }
    }
                
    //Default return value
    return false;      
  }
}


单的DaoFactory,只是q回DaoImplementationQ?br />
package net.firstpartners.rp;
/**
* Factory Method to get the Data Access Object.
* Normally we could replace this with a
* framework like Spring or Hibernate
* 得到数据存取对象的工厂方法,通常我们可以它替换为像Spring?br />*  Hibernatteq样的框?br /> */
public class DaoFactory {
  /**
   * Get the stock name Dao
   * This sample is hardcoded - in reality
   * we would make this configurable / cache
   * instances of the Dao as appropriate
   * 得到股票名字的Dao,q个例子是硬~码的-实际上我们可以让它成?br />  * 可配的,~存的合适的Dao对象?br />   * @return an instance of StockNameDao
   */
  public static StockNameDao getStockDao(){
        return new DaoImplementation();
  }
}


现在我们有了单的DAO实现来作为我们的数据库层Q那如何它与Drools商业层集成在一起呢Q最新的商业规则文gQBusinessLayer.xml会向我们展C:

<?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>
  <java:import>
    net.firstpartners.rp.DaoFactory
  </java:import>
  <java:import>
    net.firstpartners.rp.StockNameDao
  </java:import>
  <!-- Application Data not associated -->
  <!-- with any particular rule -->
  <!-- In this case it's our factory -->
  <!-- object which gives us back -->
  <!-- a handle to whatever Dao (Data -->
  <!-- access object) that we need -->
  <!-- 没有和Q何规则联pȝ应用数据Q这里是我们的工厂对象,-->
  <!—它向我们提供向后的操作,告诉我们什么Dao 是我们需要的?->

  <application-data
    identifier="daoFactory">DaoFactory
  </application-data>
  <!-- A Java (Utility) function -->
<!-- 一个JavaҎ(gu) -->
  <!-- we reference in our rules -->  
  <!-- 在我们的规则中打印跟t信?-->    
  <java:functions>
    public void printStock(
      net.firstpartners.rp.StockOffer stock)
      {
          System.out.println(
          "Name:"+stock.getStockName()
          +" Price: "+stock.getStockPrice()    
          +" BUY:"+stock.getRecommendPurchase());
      }
  </java:functions>
  <!-- Check for XYZ Corp-->  
<!-- 查XYZ公司 -->    
  <rule name="XYZCorp" salience="-1">
    <!-- Parameters we can pass into-->
<!-- the business rule -->
<!-- 可以传入规则中的参数 -->
    <parameter identifier="stockOffer">
      <class>StockOffer</class>
    </parameter">
    <!-- Conditions that must be met for -->
<!-- business rule to fire -->  
<!-- Ȁz规则必L的条g -->      
    <java:condition>
      stockOffer.getStockName().equals("XYZ")
    </java:condition>
    <java:condition>
      stockOffer.getRecommendPurchase() == null
    </java:condition>
    <java:condition>
      stockOffer.getStockPrice() > 10
    </java:condition>
        
    <!-- What happens when the business -->
<!-- rule is activated -->
<!-- 规则Ȁzd执行的步?-->
    <java:consequence>
        stockOffer.setRecommendPurchase(
        StockOffer.NO);
        printStock(stockOffer);
    </java:consequence>
  </rule>
  <!-- Ensure that negative prices -->
  <!-- are not accepted -->  
  <!-- 定负数不被接受 -->    
  <rule name="Stock Price Not Negative">
    <!-- Parameters we can pass into the -->
<!-- business rule -->
<!-- 可以传入规则中的参数 -->  
    <parameter identifier="stockOffer">
      <class>StockOffer</class>
    </parameter>
<!-- Conditions for rule to fire -->
<!-- Ȁz规则必L的条g -->    
    <java:condition>
      stockOffer.getStockPrice() < 0
    </java:condition>
  
<!--When rule is activated then ... -->
<!-- 规则Ȁzd执行的步?-->
    <java:consequence>
      stockOffer.setRecommendPurchase
        (StockOffer.NO);        
      printStock(stockOffer);
    </java:consequence>
  </rule>
  <!-- Check for Negative Prices-->  
<!-- L低h(hun) -->    
  <rule name="Stock Price Low Enough">
  <!-- Parameters for the rule -->
<!-- 可以传入规则中的参数 -->
    <parameter identifier="stockOffer">
      <class>StockOffer</class>
    </parameter>
    
<!-- Now uses Dao to get stock list -->
<!-- 现在使用Dao获取股票列表 -->
    <java:condition>
      daoFactory.getStockDao().isOnStockList(
        stockOffer.getStockName())
    </java:condition>
        
    <java:condition>
      stockOffer.getRecommendPurchase() == null
    </java:condition>
    <java:condition>
      stockOffer.getStockPrice() < 100
    </java:condition>
<!-- When rule is activated do this -->
<!-- 规则Ȁzd执行的步?-->
    <java:consequence>
        stockOffer.setRecommendPurchase(
          StockOffer.YES);      
          printStock(stockOffer);
    </java:consequence>
  </rule>
</rule-set>


Z与数据访问层集成Q该文g(相对于上一文?有几处改变:
?在最上面Q我们有几个新的<java:import>来把StockNameDao, DaoImplementation, ?DaoFactorycd入系l?br />?我们有一个新的标?lt;application-data>,它把DaoFactory的实例赋l一个变量?lt;application-data>标记cM于参敎ͼ只不q它是运用于所有商业规则,而不只是一个?br />?“股仯够低”的规则有一个新条gQ它用DaoFactory和StockNameDao来检查股是否在处理列表中?br />
我们又一ơ运行BusinessRulesTest(模拟?。模拟单元测试没有问题,既我们改变了程序的l构Q我们仍然没有改变它在做什么。从输出的日志来看,我们可以看到我们的商业规则用StockNameDao作ؓ他们评估的一部䆾Qƈ且DaoImplementation.isOnStockList()被调用了?br />虽然q个例子展示的是从数据源d信息Q其实写信息也是一L原理。如果某个规则决定应该做的话。区别在于我们的DAO会有一些setSomeInformation()的方法,一旦条件满Iq个Ҏ(gu)会在商业规则的<java:consequence>部分被调用?br />
ȝ
q篇文章中,我们展示了大多数Java服务器端的应用有的三层:表现层,商业逻辑层和数据持久化层。当框架被广泛地使用在表现层和持久层中,直到目前为止q没有框架可以包装低U的商业逻辑。就像我们在q些例子中看的,Drools和JSR-94是降低java应用复杂度,提高开发速度的理惛_选者。我希望q些例程能鼓׃去进一步接q规则引擎,他们会Z的应用的开发和l护节省不少旉?br />资源
?本文的范例代?/a>
?
Drools目主页
?[ur=http://www.jroller.com/page/eu/20040810]Drools规则的信息[/url]
?"Introduction to Drools and Rule Engines," Drools目l提?/a>
?
Drools规则的schema文g
?JSR-94: Java规则引擎概述
?Struts框架主页
?Spring框架主页
?Hibernate主页
?JUnit试框架
?
?[url=http://herzberg.ca.sandia.gov/jess/index.shtml]Jena语义与规则引?/a>
?
JSR-94主页
?Jess in Action主页
?"Business Rule Thinking" (ZJess)
?a target="_new">规则pȝ的概q?/a>
?"Jess implementation of the Rete algorithm"

Paul Browne 已经?FirstPartners.net在企业Java应用斚w作了差不?q的N


]]>
准备攑ּstruts,因ؓ它是一个拙劣的设计Q?/title><link>http://m.tkk7.com/sharkafeng/articles/59455.html</link><dc:creator>The Spark of Thinking</dc:creator><author>The Spark of Thinking</author><pubDate>Fri, 21 Jul 2006 08:59:00 GMT</pubDate><guid>http://m.tkk7.com/sharkafeng/articles/59455.html</guid><wfw:comment>http://m.tkk7.com/sharkafeng/comments/59455.html</wfw:comment><comments>http://m.tkk7.com/sharkafeng/articles/59455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/sharkafeng/comments/commentRss/59455.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/sharkafeng/services/trackbacks/59455.html</trackback:ping><description><![CDATA[     摘要: 看看别h的ȝQ前4个缺Ҏ(gu)致命的, Action c? ? ...  <a href='http://m.tkk7.com/sharkafeng/articles/59455.html'>阅读全文</a><img src ="http://m.tkk7.com/sharkafeng/aggbug/59455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/sharkafeng/" target="_blank">The Spark of Thinking</a> 2006-07-21 16:59 <a href="http://m.tkk7.com/sharkafeng/articles/59455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Drools- 商务逻辑框架的选择http://m.tkk7.com/sharkafeng/articles/59453.htmlThe Spark of ThinkingThe Spark of ThinkingFri, 21 Jul 2006 08:58:00 GMThttp://m.tkk7.com/sharkafeng/articles/59453.htmlhttp://m.tkk7.com/sharkafeng/comments/59453.htmlhttp://m.tkk7.com/sharkafeng/articles/59453.html#Feedback0http://m.tkk7.com/sharkafeng/comments/commentRss/59453.htmlhttp://m.tkk7.com/sharkafeng/services/trackbacks/59453.htmlgreenbright
原文地址:http://www.onjava.com/pub/a/onjava/2005/08/03/drools.html
中文地址:http://www.matrix.org.cn/resource/article/44/44046_Drools+Framework+Business.html
关键词: Drools Framework Business


大多数网l及企业UJave应用可以分ؓ三部分:和用户交互的前端Q和后端pȝQ比如数据库Q交互的服务层和q两部分之间的商务逻辑层。通常使用框架Q像Struts, Cocoon, Spring, Hibernate, JDO, 和实体BeansQ可以实现前端和后端的功能,但对于商务逻辑层却没有一个标准的构徏Ҏ(gu)。像EJB和Spring只能在高端实现商务逻辑构徏Q但却不能组l代码。如果我们用在配置性,可读性和重用性方面带我们极大利益的框架代曉K些纷J复杂的if...then语句Q那不是很好吗?在其他领域我们已l验证了q种利益。这文章徏议?a target="_new">Drools规则引擎作ؓ框架来解决问题?br />
下面的代码是我们试图避免的问题的例子。说明一个典型Java应用中的一些商务逻辑?br />
if ((user.isMemberOf(AdministratorGroup)
      && user.isMemberOf(teleworkerGroup))
     || user.isSuperUser(){      
         // 更多对特D案例的?br />         if((expenseRequest.code().equals("B203")
           ||(expenseRequest.code().equals("A903")
                        &&(totalExpenses<200)
                &&(bossSignOff> totalExpenses))
           &&(deptBudget.notExceeded)) {
               //付款
           } else if {
               //查许多其他的条g
           }
} else {
     //更多商务逻辑
}


我们都曾l历q相cM或者更为复杂的商务逻辑。当试图在Java中采用标准方法来实施商务逻辑Ӟ有很多问题随之而来?br />·        如果商务人员提出需要在本已很难理解的代码中加入另外一个表单("C987"Q怎么办?一旦所有的最初开发h员都在开发中Q你愿意成ؓ一个维护h员吗Q?br />·        如何认q些规则的正与否?Ҏ(gu)术h员来_从来不关注商务h员)Q检查规则的正确性是非常困难的。那么,有什么方法论来测试商务逻辑那?
许多应用有着cM的商务逻辑。如果其中一个规则发生了变化Q我们能够确认所有系l中的相关部分都要改变吗Q如果一个新应用使用了一些规则,但是也加入了一些新规则Q我们需要彻底重写逻辑吗?
·        商务逻辑嵌入在Java代码中,每次哪怕是很小的改变都需要再~译/再部|这些代码,q些商务逻辑Ҏ(gu)配置?
·        如果其他的(脚本Q语a惛_^衡现有投资在商务规则逻辑中怎么办?

J2EE/EJB和倒置控制的框Ӟ像Spring, Pico和AvalonQ让我们有能力在高端l织代码。他们很提供很好的重用性,配置性和安全性,但却不能替代上面例子中的“意大利面条式代码?/a>。理惛_Q无论我们选择那个框架Q不仅要和J2EE应用Q而且要和通常Java~程(J2SE—标准版?及广泛用的表现和持l性框架相一致。这U框架让我们能够做到Q?br />·        商务用户很容易的d验证商务逻辑?br />·        在应用中Q商务规则是可重用的和可配置的?br />·        在重负荷下,框架是可扩展的和性能良好的?br />·        Java~程人员对已存在的前端(Struts, SpringQ和后端框架Q对象关pL)很容易用这U框架?br />
另一个问题是在不同的应用中,l织面Q数据库讉K和商务逻辑的方法也是多U多L。我们的框架能够处理q个问题Qƈ能始l提升代码的重用性。理惛_Q我们的应用使用“适用所有方式的框架”。以q种方式使用框架Q能够让我们许多的应用构建的更好Q让我们可以仅关注那些对用户更有价值的部分?br />
规则引擎的营?/span>

如何解决q个问题? 一个解x案是使用规则引擎。规则引擎是l织商务逻辑的框架。它让开发者集中精力在他们有把握的事情上,而不是在一些低U机制上作决定?br />通常Q商务用户对那些能让他们理解是正的事情感到更加舒服Q相对于那些诸如?span style="COLOR: blue" twffan="done">if...then 形式来表辄事情。你从商务专安里听到的一些事情如?br />·        ?0A表单用于甌过200Ƨ元的花??br />·        “我们仅Ҏ(gu)?万或过1万的交易提供分成.?br />·        “超q?0m英镑的采购需要公司ȝ的批??br />
通过x于商务用L道是正确的事情上Q而不是怎样用Jave代码来表辑֮Q上面的说明比以前我们的代码例子要清楚的多。尽他们已l很清楚了,我们仍然需要一U机Ӟ这些规则应用到商务用户已知和作军_的事实中厅R这U机制就是规则引擎?br />
相关文章Q?/span>
在企业Java应用中用Drools
企业UJava应用开发者在表现和持l层有很多好的框架可供选择。但对于处在中间层的商务逻辑有好的框架吗Q你希望每次l理l你一个新的命令就不得不重~译那些复杂的if ... then 意大利面条代码吗Q这文章中Q保|布朗推荐的Drools的规则引擎或许是完成q类d的最好选择?br />
Jave规则引擎

JSR 94- javax.rules API制定了与规则引擎交互的通用标准Q就像JDBC能够与各U类型的数据库交互。JSR-94q不是详l说明实际规则到底是怎么写的Q而是最大限度的使用Java规则引擎来做q种详细说明?br />·        Jess可能是最成熟的Java规则引擎Q有很多好的工具Q包括EclipseQ和文档。然而它是一个商业品,q且它的规则是以序言样式W号写的Q这对许多Java~程者都是一个挑战?br />·        Jena是开源框Ӟ始于HP.它有规则引擎Qƈ且对那些x于语义的|页特别支持。但它ƈ不完全遵守JSR-94?br />·        Drools是完全遵守JSR-94的规则引擎。而且是Apache模式许可下的完全开源框架。它不仅用大家熟知的Java 和XML语法来表C则,而且有很强的用户和开发者团体。本文章中的例子中,我们用Drools。Drools使用像Java的语法,q且有最开攄许可?br />
用Drools开始开发Java应用

惌一下这U情景:在Mq篇文章几分钟后Q你的老板让你l股交易应用徏原型。尽商务用戯没有定义好商务逻辑Q一个可以想到的好主意就是用规则引擎来实现。最l的pȝ通过|络讉KQƈ且需要和后端数据库和信息pȝ交流。ؓ了开始用这个框Ӟ需要下载Drools框架Q有依赖性)。如?所C,在你喜欢的IDE中徏一个新目q确保所有的.jars文g都被引用了?br />
image
?。运行Drools必需的类?br />
׃潜在可能的巨大损失,如果我们的股交易系l想要成功,在系l中循序渐进的用一pd模拟器就昑־很重要。这L模拟器能够让你确信,即规则改变了,ql的作的军_也是正确的。我们将借用灉|工具q一些工Pq用JUnit框架作ؓ模拟器?br />
如下例所C,我们所写的W一D代码是Junit试/模拟器。尽我们不能测试所有输入系l的值的l合Q由试L什么都不测好。在q个例子中,所有的文档和classesQ包括单元测试)又在一个文件夹/包中Q但事实上,由应该创建合适的包和文g夹结构。在代码中,我们用Log4j代替System.out调用?br />
清单1:
import junit.framework.TestCase;
/*
* 应用中商务规则的JUnit试
        * q也扮演商务规则的“模拟器?让我们说明输入,验输出;q在代码?布前看看是否辑ֈ我的期望倹{?br />*/
public class BusinessRuleTest extends TestCase {
/**
*股票购买试
*/
  public void testStockBuy() throws Exception{
                
//用模拟值创?br />    StockOffer testOffer = new StockOffer();
    testOffer.setStockName("MEGACORP");
    testOffer.setStockPrice(22);
    testOffer.setStockQuantity(1000);
                
//q行规则
    BusinessLayer.evaluateStockPurchase(testOffer);
                
        //辑ֈ我们的期望吗Q?br />    assertTrue(
      testOffer.getRecommendPurchase()!=null);
    
    assertTrue("YES".equals(
      testOffer.getRecommendPurchase()));              
   }
}


q是个基本Junit试Q我们知道这个简单系l应该买q所有h(hun)g?00Ƨ元的股。很昄Q没有数据类QStockOffer.javaQ和商务层类QBusinessLayer.javaQ这个测试用例是不能~译成功的?br />
清单2:
/**
*CZ商务逻辑的正?br />*q个单示例里Q所有的商务逻辑都包含在一个类中?br />*但在现实中,按需要代理给其他的类?br />*/
public class BusinessLayer {

        /**
   *评h(hun)购买q支股票是否是个好主?br />   *@参数 stockToBuy
   *@return 如果推荐购买股票q回真,否则q回?br />   */
  public static void evaluateStockPurchase
    (StockOffer stockToBuy){
                return false;
  }
}
StockOffercd下所C:
/**
* 单的JavaBean保存StockOffer倹{?br />* 一个’股出价’就是别人卖(公司股䆾Q所l出的h(hun)根{?br />*/
public class StockOffer {
        
  //帔R
  public final static String YES="YES";
  public final static String NO="NO";

  //内部变量
  private String stockName =null;
  private int stockPrice=0;
  private int stockQuantity=0;
  private String recommendPurchase = null;

/**
   * @q回股票名称
   */

  public String getStockName() {
        return stockName;
  }
/**
   * @参数 stockName 讄股票名称.
   */
  public void setStockName(String stockName) {
        this.stockName = stockName;
  }
/**
   * @return q回股票h.
   */

  public int getStockPrice() {
        return stockPrice;
  }
/**
   * @参数 stockPrice讄股票h.
   */

  public void setStockPrice(int stockPrice) {
        this.stockPrice = stockPrice;
  }
/**
   * @return q回股票数量.
   */

  public int getStockQuantity() {
        return stockQuantity;
  }
/**
   * @参数 stockQuantity 讄股票数量.
   */

  public void setStockQuantity(int stockQuantity){
        this.stockQuantity = stockQuantity;
  }
/**
   * @return q回购买.
   */

  public String getRecommendPurchase() {
        return recommendPurchase;
  }
}


在我们熟(zhn)的IDE的Junit中运行BusinessRuleTest。如果你不太熟?zhn)JunitQ可以从Junit|站获取更多信息。如?所C,毫不奇怪的是,׃没有准备好适当的商务逻辑Q测试在W二个申明处p|了。这个确信了模拟?单元试重点加强了他们应该有的问题?br />
image
?。Junit试l果

用规则描q商务逻辑

现在Q我们需要描qC些商务逻辑Q像“如果股h(hun)g?00Ƨ元Q应该购买。?br />q样我们修改BusinessLayer.java为:

清单3:
import java.io.IOException;
import org.drools.DroolsException;
import org.drools.RuleBase;
import org.drools.WorkingMemory;
import org.drools.event.DebugWorkingMemoryEventListener;
import org.drools.io.RuleBaseLoader;
import org.xml.sax.SAXException;
/**
*CZ商务逻辑的正?br />*q个单示例里Q所有的商务逻辑都包含在一个类中?br />*但在现实中,按需要代理给其他的类?br />*@作?~省
*/
public class BusinessLayer {
//包含规则文g的名?br />  private static final String BUSINESS_RULE_FILE=
                              "BusinessRules.drl";
        //内部处理的规则基
  private static RuleBase businessRules = null;
/**
* 如果q没有装载商务规则的话就装蝲它?br />*@抛出异常 -通常从这里恢?br />*/
  private static void loadRules()
                       throws Exception{
    if (businessRules==null){
      businessRules = RuleBaseLoader.loadFromUrl(
          BusinessLayer.class.getResource(
          BUSINESS_RULE_FILE ) );
    }
  }    
        
/**
   *评h(hun)是否购买q支股票
   *@参数 stockToBuy
   *@return 如果推荐购买股票q回真,否则q回?br />   *@抛出异常
   */
  public static void evaluateStockPurchase
       (StockOffer stockToBuy) throws Exception{
                
//保商务规则被装?br />    loadRules();
//一些程序进行的日志
    System.out.println( "FIRE RULES" );
    System.out.println( "----------" );
        //了解以前q行的状?br />    WorkingMemory workingMemory
            = businessRules.newWorkingMemory();
//规则集可以d调试侦听?br />    workingMemory.addEventListener(
      new DebugWorkingMemoryEventListener());
        //让规则引擎了解实?br />    workingMemory.assertObject(stockToBuy);
        //让规则引擎工?br />    workingMemory.fireAllRules();
  }
}


q个cL许多重要的方法:
·        loadRules()Ҏ(gu)装蝲BusinessRules.drl文g中的规则?br />·        更新的evaluateStockPurchase()Ҏ(gu)评h(hun)q些商务规则。这个方法中需要注意的是:
·        同一个RuleSet可以被重复用(内存中的商务规则是无状态的Q?br />·        ׃以我们的知识我们知道什么是正确的,每次评h(hun)我们使用一个新的WorkingMemorycR在内存中用assertObject()Ҏ(gu)存放已知的实事(作ؓJava对象Q?br />·        Drools有一个事件侦听模式,能让我们“看到“事件模式内到底发生了什么事情。在q里我们用它打印试信息。Working memorycȝfireAllRules()Ҏ(gu)让规则被评h(hun)和更斎ͼ在这个例子中Qstock offerQ?br />
再次q行例子之前Q我们需要创建如下BusinessRules.drl文gQ?br />
清单4:
<?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>


q个规则文g有几个有意思的部分Q?br />·        在XML-Schema定义被引入Java对象后,我们也把它引入到我们的规则中。这些对象来自于所需的Javacd?br />·        功能和标准的Java代码相结合。这L话,我们可以通过功能日志了解到底发生了什么?br />·        规则讄可以包括一个或多个规则?br />·        每条规则可以有参敎ͼStockOfferc)。需要满一个或多个条gQƈ且当条g满时就执行相应的结果?br />
修改Q编译了代码后,再运行Junit试模拟器。这ơ,如图3所C,商务规则被调用了Q逻辑评h(hun)正确Q测试通过。祝贺—你已经创徏了你的第一个基于规则的应用Q?br />
image
?。成功的Junit试

灉|的规?/span>

刚徏好系l,你示范了上面的原型给商务用户Q这时他们想起先前忘了给你提到几个规则了。新规则之一是当数量是负值时Q不能够交易股票。你说“没问题Q”,然后回到你的座位Q借可靠的知识Q你能迅速的改进pȝ?br />W一件要做的事情是更C的模拟器Q把下面的代码加到BusinessRuleTest.java:

清单5:

/**
*试买股确保系l不接受负?br />*/
  public void testNegativeStockBuy()
                                throws Exception{
//用模拟值创?br />      StockOffer testOffer = new StockOffer();
        testOffer.setStockName("MEGACORP");
        testOffer.setStockPrice(-22);
        testOffer.setStockQuantity(1000);
//q行规则
        BusinessLayer
              .evaluateStockPurchase(testOffer);
//是否辑ֈ我们的期望?
        assertTrue("NO".equals(
          testOffer.getRecommendPurchase()));
}


q是为商务用hq的新规则的试。如果测试这个Junit试Q如预期的新试p|了。我们需要加q个新规则到.drl文g中,如下所C?br />
清单6:
<!-- Ensure that negative prices 
                            are not accepted-->      
  <rule name="Stock Price Not Negative">
    <!-- Parameters we can pass into
                          the business rule -->
    <parameter identifier="stockOffer">
      <class>StockOffer</class>
    </parameter>
    <!-- Conditions or 'Left Hand Side' (LHS)
       that must be met for rule to fire -->
    <java:condition>
      stockOffer.getStockPrice() < 0
    </java:condition>
    <!-- What happens when the business rule
                              is activated -->
    <java:consequence>
      stockOffer.setRecommendPurchase(
                                  StockOffer.NO);      
      printStock(stockOffer);
    </java:consequence>
  </rule>


q个规则的和前一个类|期望<java:condition>不同Q测试负|?lt;java:consequence>讄购买为No。再ơ运行测?模拟器,q次试通过?br />
q样的话Q如果你习惯使用q程~程Q象大多数Java ~程者)Q或怽会发愁挠_一个文件包含两个独立的商务规则Q而且我们也没有告诉规则引擎这两个规则哪个更重要。然而,股票hQ?22Q也W合两个规则Q它?yu)?也小?00Q。不论如何,我们得到了正的l果Q即使交换规则的序。这是怎么工作的那Q?br />
下面控制台输出的摘录帮助我们明白到底发生了什么。我们看C个规则都被触发了Q[activationfired]行)q且Recommend Buy先被|ؓYes然后被置为No。Drools是如何以正确的顺序来触发q些规则的那Q如果你看Stock Price Low Enough规则Q就会看到其中的一个条件recommendPurchase()是null.q就以让Drools军_Stock Price Low Enough规则应该先于Stock Price Not Negative规则触发。这个过E就是冲H解x案?br />
清单7:
FIRE RULES
----------
[ConditionTested: rule=Stock Price Not Negative;
  condition=[Condition: stockOffer.getStockPrice()
  < 0]; passed=true; tuple={[]}]
[ActivationCreated: rule=Stock Price Not Negative;
  tuple={[]}]
[ObjectAsserted: handle=[fid:2];
   object=net.firstpartners.rp.StockOffer@16546ef]
[ActivationFired: rule=Stock Price Low Enough;
   tuple={[]}]
[ActivationFired: rule=Stock Price Not Negative;
   tuple={[]}]
Name:MEGACORP Price: -22 BUY:YES
Name:MEGACORP Price: -22 BUY:NO


如果你是个过E编E者,无论你认是多聪明Q你仍然不能完全的信d。这是ؓ什么我们用单元测?模拟器:“辛苦的”Junit试Q用通用Java代码Q保证规则引擎用我们x的行来做军_。(不要p上亿在一些无价值的股票上!Q同Ӟ规则引擎的强大和灉|性让我们能够q速开发商务逻辑?br />E后Q我们将看到更多冲突解决Ҏ(gu)的经典的方式?br />
冲突解决Ҏ(gu)

在商务这边,Z真的印象深刻q别开始通过可能的选择来思考。他们看到XYZ公司股票的问题ƈ且决定执行一条新规则:如果XYZ公司的股价低?0Ƨ元Q就仅仅买XYZ公司的股?br />象上ơ,加测试到模拟器中Q在规则文g中加入新的商务规则,如下所列。首先,在BusinessRuleTest.java中添加新Ҏ(gu)?br />
清单8:
/**
*保pȝpȝ在XYZ公司股h(hun)便宜时就购买他们的股?br />*/
public void testXYZStockBuy() throws Exception{
//用模拟值创?br />  StockOffer testOfferLow = new StockOffer();
  StockOffer testOfferHigh = new StockOffer();
                
  testOfferLow.setStockName("XYZ");
  testOfferLow.setStockPrice(9);
  testOfferLow.setStockQuantity(1000);
                
  testOfferHigh.setStockName("XYZ");
  testOfferHigh.setStockPrice(11);
  testOfferHigh.setStockQuantity(1000);
//q行规则
  BusinessLayer.evaluateStockPurchase(
    testOfferLow);
  assertTrue("YES".equals(
    testOfferLow.getRecommendPurchase()));
                
  BusinessLayer.evaluateStockPurchase(
    testOfferHigh);
  assertTrue("NO".equals(
    testOfferHigh.getRecommendPurchase()));            
}


然后Q在BusinessRules.drl中加个新<规则>:

清单10:
  
<rule name="XYZCorp" salience="-1">
   <!-- Parameters we pass to rule -->
   <parameter identifier="stockOffer">
     <class>StockOffer</class>
   </parameter>
    
   <java:condition>
     stockOffer.getStockName().equals("XYZ")
   </java:condition>
   <java:condition>
     stockOffer.getRecommendPurchase() == null
   </java:condition>
   <java:condition>
     stockOffer.getStockPrice() > 10
   </java:condition>
        
   <!-- What happens when the business
                                rule is activated -->
   <java:consequence>
     stockOffer.setRecommendPurchase(
       StockOffer.NO);  
     printStock(stockOffer);
   </java:consequence>
  </rule>


注意到商务规则文件中Q规则名字后Q我们设|salience?1Q比如,到现在我们说明的所有规则中的最低优先Q。系l冲H(意味着Drools在触发那个规则的序上作军_Q的大多数规则给Z达到的规则的条件。缺省的军_Ҏ(gu)如下Q?
·        显著?如上列出的我们分配的倹{?
·        崭新性:我们使用规则的次数?
·        复杂性:W一ơ触发的更复杂的特定规则?
·        装蝲序Q那个规则被装蝲的顺序?br />如果我们不说明这个例子中规则的显著性,会发生的是Q?
·        XYZ公司规则Q“如果股h(hun)Dq?0Ƨ元买XYZ”)被首先触发Q推荐买标记的状态被|ؓNoQ?
·        然后是更多的普通规则被触发Q“买所有低?00的股”)Q推荐买标记的状态被|ؓyes?br />
q将得到我们不期望的l果。然而,我们的例子设|了显著性因素,用例及商务规则就会如我们期望的运行了?br />
大多数情况下Q书写清楚的规则且设|显著性将为Drools提供_的信息来选择触发规则的顺序。有Ӟ我们x个的改变解决规则冲突的方式。以下是一个如何改变的例子Q其中我告诉规则引擎首先触发最单的规则。要注意的是Q改变冲H解x案是要小心,因ؓ它能Ҏ(gu)的改变规则引擎的规则—用清楚的写得恰当的规则能预先解册多问题?br />
清单11:
//生成冲突解决者的列表
  ConflictResolver[] conflictResolvers =
    new ConflictResolver[] {
      SalienceConflictResolver.getInstance(),
      RecencyConflictResolver.getInstance(),
        SimplicityConflictResolver.getInstance(),
        LoadOrderConflictResolver.getInstance()
    };
//包装成合成解册?br />  CompositeConflictResolver resolver =
    new CompositeConflictResolver(
      conflictResolvers);
//当装载规则时Q说明这个解册?br />  businessRules = RuleBaseLoader.loadFromUrl(
    BusinessLayer.class.getResource(
      BUSINESS_RULE_FILE),resolver);


对于我们的简单的应用Q由Junit试驱动Q我们不需要改变Drools解决规则冲突的方式。了解冲H解x案是如何工作的对我们是非常有帮助的,其是当应用需要满x复杂根严格的需求试?br />
l论

q篇文章了许多编E者遇到过的问题:如何定制复杂的商务逻辑。我们示范了一个用Droolsx案的单应用ƈ介绍了基于规则编E的概念Q包括在q行时这些规则是如何被处理的。稍后,接下来的文章以q些为基来展C在企业UJava应用中是如何使用它的?br />

资源
·下蝲例子所有源代码:源代?/a>
·Matrix-Java开发者社?
http://www.matrix.org.cn
·onjava.com:onjava.com
·Drools目主页
·Drools规则信息
·“Drools和规则引擎介l”由Drools目领导
·Drools规则计划文g
·JSR-94, Java规则引擎Q概?
·Jess Jave规则引擎
·Jena语义和规则引?/a>
·
JSR-94主页
·Jess在Action主页
·“商务规则思想”(ZJessQ?/a>
·
“规则系l的一般介l?
·“Rete法的Jess执行?/a>

保尔 布朗已经通过FirstPartners.net|站Z业Java咨询了约7q的旉?br />

]]>
Java规则引擎与其API应用详解(?http://m.tkk7.com/sharkafeng/articles/59449.htmlThe Spark of ThinkingThe Spark of ThinkingFri, 21 Jul 2006 08:57:00 GMThttp://m.tkk7.com/sharkafeng/articles/59449.htmlhttp://m.tkk7.com/sharkafeng/comments/59449.htmlhttp://m.tkk7.com/sharkafeng/articles/59449.html#Feedback0http://m.tkk7.com/sharkafeng/comments/commentRss/59449.htmlhttp://m.tkk7.com/sharkafeng/services/trackbacks/59449.html本文对Java规则引擎与其API(JSR-94)及相兛_现做了较详细的介l,对其体系l构和API应用有较详尽的描qͼq指出Java规则引擎,规则语言QJSR-94的相互关p?以及JSR-94的不之处和展望?

  复杂企业U项目的开发以及其中随外部条g不断变化的业务规?business logic),q切需要分d业决{者的商业决策逻辑和应用开发者的技术决{,q把q些商业决策攑֜中心数据库或其他l一的地方,让它们能在运行时Q即商务旉Q可以动态地理和修改从而提供Y件系l的柔性和适应性。规则引擎正是应用于上述动态环境中的一U解x法?/p>

  本文W一部分要介l了规则引擎的生背景和Z规则的专家系l,W二部分介绍了什么是规则引擎及其架构和算法,W三部分介绍了商业品和开源项目实现等各种Java规则引擎Q第四部分对Java规则引擎APIQJSR-94Q作了详l介l,讲解了其体系l构Q管理API和运行时API及相兛_全问题,W五部分则对规则语言及其标准化作了探讨,W六部分l出了一个用Java规则引擎API的简单示例,W七部分l予结和展望?/p>

  1?介绍

  1.1 规则引擎产生背景

  企业理者对企业UITpȝ的开发有着如下的要求:(1)为提高效率,理程必须自动化,即C商业规则异常复杂(2)市场要求业务规则l常变化QITpȝ必须依据业务规则的变化快速、低成本的更?3)Z快速、低成本的更斎ͼ业务人员应能直接理ITpȝ中的规则Q不需要程序开发h员参与?/p>

  而项目开发h员则到了以下问?(1)E序=法+数据l构Q有些复杂的商业规则很难推导出算法和抽象出数据模?2)软g工程要求从需?>设计->~码Q然而业务规则常常在需求阶D可能还没有明确Q在设计和编码后q在变化Q业务规则往往嵌在pȝ各处代码?3)对程序员来说Q系l已l维护、更新困难,更不可能让业务h员来理?/p>

  Z规则的专家系l的出现l开发h员以解决问题的契机。规则引擎由Z规则的专家系l中的推理引擎发展而来。下面简要介l一下基于规则的专家pȝ?/p>

  1.2 Z规则的专家系l?RBES)

  专家pȝ是h工智能的一个分支,它模仿hcȝ推理方式Q用试探性的Ҏ(gu)q行推理Qƈ使用人类能理解的术语解释和证明它的推理结论。专家系l有很多分类Q神l网l、基于案例推理和Z规则pȝ{?/p>

  RBES包括三部分:Rule BaseQknowledge baseQ、Working MemoryQfact baseQ和Inference EngineQ推理引擎)。它们的l构如下所C:

  ?.Z规则的专家系l组?/p>


  如上图所C,推理引擎包括三部分:Pattern Matcher、Agenda和Execution Engine。Pattern Matcher何时执行哪个规则QAgenda理PatternMatcher挑选出来的规则的执行次序;Execution Engine负责执行规则和其他动作?/p>

  推理引擎通过军_哪些规则满事实或目标,q授予规则优先Q满事实或目标的规则被加入议程。存在两者推理方式:演绎法(Forward-Chaining正向链)和归UxQBackward-Chaining反向链)。演l法从一个初始的事实出发Q不断地应用规则得出l论Q或执行指定的动作)。而归Ux则是从假讑և发,不断地寻扄合假讄事实?/p>

  2?规则引擎

  2.1 业务规则
 
  一个业务规则包含一l条件和在此条g下执行的操作Q它们表CZ务规则应用程序的一D业务逻辑。业务规则通常应该׃务分析h员和{略理者开发和修改Q但有些复杂的业务规则也可以由技术h员用面向对象的技术语a或脚本来定制。业务规则的理论基础?讄一个或多个条gQ当满q些条g时会触发一个或多个操作?/p>

  2.2 规则引擎

  什么是规则引擎Q规则引擎是如何执行规则的?q可以称之ؓ"什??如何"的问题。到底规则引擎是什么还是目前业界一个比较有争议的问题,在JSR-94U也几乎没有定义。可以这栯为充分定义和解决?如何"的问题,"什?问题本质上也q刃而解。也许这又是一U?先有蛋还是先有鸡"哲学争论。今后标准规则语a的定义和推出及相x准的制定应该可以l这L问题和争论划上一个句受本文中Q暂且这栯说什么是规则引擎Q规则引擎由推理引擎发展而来Q是一U嵌入在应用E序中的lgQ实C业务决{从应用E序代码中分d来,q用预定义的语义模块编写业务决{。接受数据输入,解释业务规则QƈҎ(gu)规则做出业务决策?/p>

  2.3 规则引擎的用方?/strong>

  ׃规则引擎是Y件组Ӟ所以只有开发h员才能够通过E序接口的方式来使用和控制它Q规则引擎的E序接口臛_包含以下几种APIQ加载和卸蝲规则集的APIQ数据操作的APIQ引擎执行的API。开发h员在E序中用规则引擎基本遵循以?个典型的步骤Q创则引擎对象;向引擎中加蝲规则集或更换规则集;向引擎提交需要被规则集处理的数据对象集合Q命令引擎执?导出引擎执行l果Q从引擎中撤出处理过的数据。用了规则引擎之后Q许多涉及业务逻辑的程序代码基本被q五个典型步骤所取代?

  一个开攄业务规则引擎应该可以"嵌入"在应用程序的M位置Q不同位|的规则引擎可以使用不同的规则集Q用于处理不同的数据对象。此外,对用引擎的数量没有限制?/p>

  2.4 规则引擎架构与推?/strong>

  规则引擎的架构如下图所C:

  ?. 业务规则引擎架构


  规则引擎的推理步骤如下:a. 初始数据(factQ输入至工作内存(Working Memory)。b. 使用Pattern Matcher规则库(Rules repository)中的规则QruleQ和数据QfactQ比较。c. 如果执行规则存在冲突QconflictQ,卛_时激zM多个规则Q将冲突的规则放入冲H集合。d. 解决冲突Q将Ȁzȝ规则按顺序放入Agenda。e. 执行Agenda中的规则。重复步骤b至eQ直到执行完毕Agenda中的所有规则?/span>

  M一个规则引擎都需要很好地解决规则的推理机制和规则条g匚w的效率问题?/p>

  当引擎执行时Q会Ҏ(gu)规则执行队列中的优先序逐条执行规则执行实例Q由于规则的执行部分可能会改变工作区的数据对象,从而会佉K列中的某些规则执行实例因为条件改变而失效,必须从队列中撤销Q也可能会激zd来不满条g的规则,生成新的规则执行实例q入队列。于是就产生了一U?动?的规则执行链QŞ成规则的推理机制。这U规则的"铑ּ"反应完全是由工作Z的数据驱动的?

  规则条g匚w的效率决定了引擎的性能Q引擎需要迅速测试工作区中的数据对象Q从加蝲的规则集中发现符合条件的规则Q生成规则执行实例?982q美国卡耐基·梅隆大学的Charles L. Forgy发明了一U叫Rete法Q很好地解决了这斚w的问题。目前世界顶的商用业务规则引擎产品基本上都使用Rete法?/p>

  2.5 规则引擎的算?/strong>
 
  大部分规则引擎品的法Q基本上都来自于Dr. Charles Forgy?979q提出的RETE法及其变体QRete法是目前效率最高的一个Forward-Chaining推理法QDrools目是Rete法的一个面向对象的Java实现QRete法其核心思想是将分离的匹配项Ҏ(gu)内容动态构造匹配树Q以辑ֈ显著降低计算量的效果?/p>

  3?Java规则引擎
 
  目前L的规则引擎组件多是基于Java和C++E序语言环境Q已l有多种Java规则引擎商业产品与开源项目的实现Q其中有的已l支持JSR94Q有的正朝这个方向做出努力,列出如下Q?/p>

  3.1 Java规则引擎商业产品

  Java规则引擎商业产品主要有(Jess不是开源项目,它可以免费用于学术研IӞ但用于商业用途则要收费)Q?/p>

  3.2 Java规则引擎开源项?/span>

  开源项目的实现主要包括Q?/p>

  Drools - Drools规则引擎应用Rete法的改qŞ式Rete-II法。从内部机制上讲Q它使用了和Forgy的算法相同的概念和方法,但是增加了可与面向对象语a无缝q接的节点类型?/p>

  Mandarax Z反向推理Q归UxQ。能够较Ҏ(gu)地实现多个数据源的集成。例如,数据库记录能方便地集成ؓ事实?facts sets)Qreflection用来集成对象模型中的功能。目前不支持JSR 94

  OFBiz Rule Engine - 支持归纳?Backward chaining).最初代码基于Steven John Metsker?Building Parsers in Java"Q不支持JSR 94

  JLisa - JLisa是用来构Z务规则的强大框架Q它有着扩展了LISP优秀特色的优?比Clipsq要强大.q些特色对于多范例Y件的开发是臛_重要?支持JSR 94

  其它的开源项目实现有诸如Algernon, TyRuBa, JTP, JEOPS, InfoSapient, RDFExpert, Jena 2, Euler, JLog, Pellet OWL Reasoner, Prova, OpenRules, SweetRules, JShop2{等?/p>

  4?Java规则引擎API(JSR-94)

  4.1 ?/strong>

  q去大部分的规则引擎开发ƈ没有规范化,有其自有的APIQ这使得其与外部E序交互集成不够灉|。{而用另外一U品时往往意味需要重写应用程序逻辑和API调用Q代仯大。规则引擎工业中标准的缺乏成Zo人关注的重要斚w?003q?1月定Eƈ?004q?月最l发布的JSR 94QJava规则引擎APIQ得Java规则引擎的实现得以标准化?/p>

  Java规则引擎API由javax.rules包定义,是访问规则引擎的标准企业UAPI。Java规则引擎API允许客户E序使用l一的方式和不同厂商的规则引擎品交互,像使用JDBC~写独立于厂商访问不同的数据库品一栗Java规则引擎API包括创徏和管理规则集合的机制Q在Working Memory中添加,删除和修改对象的机制Q以及初始化Q重|和执行规则引擎的机制?/p>

  4.2 介Java规则引擎API体系l构

  Java规则引擎API分ؓ两个主要部分:q行时客户API(the Runtime client API)和规则管理API(the rules administration API)?/p>

  4.2.1规则理API

  规则理API在javax.rules.admin中定?包括装蝲规则以及与规则对应的动作(执行?execution sets)以及实例化规则引擎。规则可以从外部资源中装?比如说URI,Input streams, XML streams和readers{等.同时理API提供了注册和取消注册执行集以及对执行集进行维护的机制。用admin包定义规则有助于对客戯问运行规则进行控制管?它通过在执行集上定义许可权使得未经授权的用h法访问受控规则?/p>

  理API使用cRuleServiceProvider来获得规则管?RuleAdministrator)接口的实?规则理接口提供Ҏ(gu)注册和取消注册执行集.规则理?RuleAdministrator)提供了本地和q程的RuleExecutionSetProvider.在前面已提及,RuleExecutionSetProvider负责创徏规则执行?规则执行集可以从如XML streams, input streams{来源中创徏.q些数据来源及其内容l汇集和序列化后传送到q程的运行规则引擎的服务器上.大多数应用程序中,q程规则引擎或远E规则数据来源的情况q不多见.Z避免q些情况中的|络开销,API规定了可以从q行在同一JVM中规则库中读取数据的本地RuleExecutionSetProvider.

  规则执行集接口除了拥有能够获得有兌则执行集的方?q有能够索在规则执行集中定义的所有规则对?q得客戯够知道规则集中的规则对象q且按照自己需要来使用它们?

  4.2.2 q行时API

  q行时API定义在javax.rules包中,则引擎用戯行规则获得结果提供了cdҎ(gu)。运行时客户只能讉K那些使用规则理API注册q的规则Q运行时API帮助用户获得规则对话q且在这个对话中执行规则?/p>

  q行时API提供了对厂商规则引擎API实现的类gJDBC的访问方?规则引擎厂商通过cRuleServiceProvider(cRuleServiceProvider提供了对具体规则引擎实现的运行时和管理API的访?其规则引擎实现提供l客?q获得RuleServiceProvider唯一标识规则引擎的URL.

  URL推荐标准用法是用类?com.mycompany.myrulesengine.rules.RuleServiceProvider"q样的Internet域名I间,q将有助于访问URL的唯一?cRuleServiceProvider内部实现了规则管理和q行时访问所需的接?所有的RuleServiceProvider要想被客h讉K都必ȝRuleServiceProviderManagerq行注册。注册方式类gJDBC API的DriverManager和Driver?/p>

  q行时接口是q行时API的关键部?q行时接口提供了用于创徏规则会话(RuleSession)的方?规则会话如前所q是用来q行规则?q行时API同时也提供了讉K在service provider注册q的所有规则执行集(RuleExecutionSets).规则会话接口定义了客户用的会话的类?客户Ҏ(gu)自己q行规则的方式可以选择使用有状态会话或者无状态会话?/p>

  无状态会话的工作方式像一个无状态会话bean.客户可以发送单个输入对象或一列对象来获得输出对象.当客户需要一个与规则引擎间的专用会话?有状态会话就很有?输入的对象通过addObject() Ҏ(gu)可以加入C话当?同一个会话当中可以加入多个对?对话中已有对象可以通过使用updateObject()Ҏ(gu)得到更新.只要客户与规则引擎间的会话依然存?会话中的对象׃会丢失?/p>

  RuleExecutionSetMetaData接口提供l客戯其查找规则执行集的元数据(metadata).元数据通过规则会话接口(RuleSession Interface)提供l用戗?/p>

  使用q行时Runtime API的代码片断如下所C?

RuleServiceProvider ruleProvider = RuleServiceProviderManager.getRuleServiceProvider   
  ("com.mycompany.myrulesengine.rules. RuleServiceProvider");
RuleRuntime ruleRuntime = ruleProvider.getRuleRuntime();
StatelessRuleSession ruleSession = (StatelessRuleSession)ruleRuntime.createRuleSession(ruleURL,    null, RuleRuntime.STTELESS_SESSION_TYPE);
List inputRules = new ArrayList();
inputRules.add(new String("Rule 1"));
inputRules.add(new Integer(1));
List resultRules = ruleSession.executeRules(inputRules);

  4.3 Java规则引擎API安全问题
  
  规则引擎API管理API和运行时API加以分开,从而ؓq些包提供了较好_度的安全控?规则引擎APIq没有提供明昄安全机制,它可以和J2EE规范中定义的标准安全API联合使用.安全可以׃下机制提?如Java authentication and authorization service (JAAS),the Java cryptography extension (JCE),Java secure Socket Extension (JSSE),或者其它定制的安全API.JAAS能被用来定义规则执行集的许可权限,从而只有授权用h能访问?/p>

  4.4 异常与日?/strong>

  规则引擎API定义了javax.rules.RuleException作ؓ规则引擎异常层次的根c?所有其它异帔Rl承于这个根c?规则引擎中定义的异常都是受控制的异常(checked exceptions),所以捕获异常的d׃l了规则引擎。规则引擎API没有提供明确的日志机?但是它徏议将Java Logging API用于规则引擎API?/p>

  4.5 JSR 94 结

  JSR 94 则引擎提供了公用标准API,仅仅为实现规则管理API和运行时API提供了指D?q没有提供规则和动作该如何定义以及该用什么语a定义规则,也没有ؓ规则引擎如何d评h(hun)规则提供技术性指?JSR 94规范?yu)上q问题留l了规则引擎的厂?在下一节我简要介l一下规则语a?/p>

  5?规则语言

  JSR 94中没有涉及用来创则和动作的语a.规则语言是规则引擎应用程序的重要l成部分,所有的业务规则都必ȝ某种语言定义q且存储于规则执行集?从而规则引擎可以装载和处理他们?/p>

  ׃没有关于规则如何定义的公用规?市场上大多数行的规则引擎都有其自己的规则语aQ目前便有许多种规则语言正在应用Q因此,当需要将应用UL到其他的Java规则引擎实现Ӟ可能需要变换规则定义,如将DroolsU有的DRL规则语言转换成标准的ruleMLQJess规则语言转换成ruleML{。这个工作一般由XSLT转换器来完成?/p>

  多种规则语言的用得不同规则引擎实C间的兼容性成为问?通用的规则引擎API或许可以减轻不同厂家API之间的问?但公用规则语a的缺乏将仍然ȝ不同规则引擎实现之间的互操作?管业界在提出公用规则语a上做Z一些努? 比如说RuleML,SRML的出?但距获得绝大部分规则引擎厂商同意的公用标准q有很长的\要走?/p>

  6?Java规则引擎API使用CZ

  6.1 讄规则引擎

  Java规则引擎的管理活动阶D开始于查找一个合适的javax.rules.RuleServiceProvider对象Q这个对象是应用E序讉K规则引擎的入口。在J2EE环境中,你可能可以通过JNDI获得RuleServiceProvider。否则,你可以用javax.rules.RuleServiceProviderManagerc:

javax.rules.RuleServiceProviderManager class:
String implName = "org.jcp.jsr94.ri.RuleServiceProvider";
Class.forName(implName);
RuleServiceProvider serviceProvider = RuleServiceProviderManager.getRuleServiceProvider

  拥有了RuleServiceProvider对象Q你可以获得一个javax.rules.admin.RuleAdministratorcR从RuleAdministratorcMQ你可以得到一个RuleExecutionSetProviderQ从cd可以知道Q它用于创徏javax.rules.RuleExecutionSets对象。RuleExecutionSet基本上是一个装入内存的Q准备好执行的规则集合?/p>

  包javax.rules.admin包括两个不同的RuleExecutionSetProvidercRRuleExecutionSetProvidercLw包括了从Serializable对象创徏RuleExecutionSets的方法,因此在规则引擎位于远E服务器的情况下Q仍然可以用RuleExecutionSetProviderc,构造器的参数可以通过RMI来传递。另一个类是LocalRuleExecutionSetProviderQ包含了其他Ҏ(gu)Q用于从非Serializable资源Q如java.io.ReaderQ本地文Ӟ创徏RuleExectionSets。假设拥有了一个RuleServiceProvider对象Q你可以从本地文件rules.xml文g创徏一个RuleExectionSet对象。如以下的代码所C:

RuleAdministrator admin = serviceProvider.getRuleAdministrator();
HashMap properties = new HashMap();
properties.put("name", "My Rules");
properties.put("description", "A trivial rulebase");
FileReader reader = new FileReader("rules.xml");
RuleExecutionSet ruleSet = null;
 try {
    LocalRuleExecutionSetProvider lresp =admin.getLocalRuleExecutionSetProvider(properties);
ruleSet = lresp.createRuleExecutionSet(reader, properties);
 } finally {
  reader.close();
 }

  接下来,你可以用RuleAdministrator注册获得的RuleExecutionSetQƈl它分配一个名U。在q行Ӟ你可以用同一个名U创Z个RuleSessionQ该RuleSession使用了这个命名的RuleExecutionSet。参见下面的用法Qadmin.registerRuleExecutionSet("rules", ruleSet, properties);

  6.2 执行规则引擎

  在运行时阶段Q你可以参见一个RuleSession对象。RuleSession对象基本上是一个装载了特定规则集合的规则引擎实例。你从RuleServiceProvider得到一个RuleRuntime对象Q接下来Q从javax.rules.RuleRuntime得到RuleSession对象?/p>

  RuleSession分ؓ两类Qstateful和stateless。它们具有不同的功能。StatefulRuleSession的Working Memory能够在多个方法调用期间保存状态。你可以在多个方法调用期间在Working Memory中加入多个对象,然后执行引擎Q接下来q可以加入更多的对象q再ơ执行引擎。相反,StatelessRuleSessioncL不保存状态的Qؓ了执行它的executeRulesҎ(gu)Q你必须为Working Memory提供所有的初始数据Q执行规则引擎,得到一个内容列表作回倹{?/p>

  下面的例子中Q我们创Z个StatefulRuleSession实例Q添加两个对象(一个Integer和一个StringQ到Working MemoryQ执行规则,然后得到Working Memory中所有的内容Q作为java.util.List对象q回。最后,我们调用releaseҎ(gu)清理RuleSessionQ?/p>
RuleRuntime runtime = rsp.getRuleRuntime();
StatefulRuleSession session=(StatefulRuleSession)runtime.createRuleSession("rules",           properties,RuleRuntime.STATEFUL_SESSION_TYPE); 
session.addObject(new Integer(1));
session.addObject("A string");
session.executeRules();
List results = session.getObjects();
session.release();

  7?l束?/strong>

  Java规则引擎API(JSR-94)允许客户E序使用l一的方式和不同厂商的规则引擎品交互,一定程度上l规则引擎厂商提供了标准化规范。但其几乎没有定义什么是规则引擎Q当然也没有深入到规则是如何构徏和操U늚Q规则调用的效用Q规则与Java语言的绑定等斚w。ƈ且JSR-94在对J2EE的支持上也不뀂规则语a的标准化QJSR-94的进一步的充实深化都有待研I?/p>

]]>
从?-4q的.Net开发经验”想到的(?http://m.tkk7.com/sharkafeng/articles/59276.htmlThe Spark of ThinkingThe Spark of ThinkingThu, 20 Jul 2006 10:20:00 GMThttp://m.tkk7.com/sharkafeng/articles/59276.htmlhttp://m.tkk7.com/sharkafeng/comments/59276.htmlhttp://m.tkk7.com/sharkafeng/articles/59276.html#Feedback0http://m.tkk7.com/sharkafeng/comments/commentRss/59276.htmlhttp://m.tkk7.com/sharkafeng/services/trackbacks/59276.html我msn上有个朋友是做hr的,l常在他名字后面写一些招聘信息什么的。今天上来也不例外,说是要找?Q?q”工作经验的.Net开发h员?/p>

当然我不知道他们公司是怎么想的Q不q我惛_中国x真正3-4q工作经验的.Net开发h员恐怕基本上找不刎ͼ是扑ֈ几个恐怕也有一大半是吹的。因?Net从成型到现在估计也就3?q时_可能q不刎ͼ。更不要说大规模开始应用了?/p>

以前q看q一个招聘高UJ2EE工程师的q告Q当然了Q“高U”就是不一P要求臛_?Q?qJ2EE开发经验。而大家当焉知道Q?q前?999q_J2EE才刚刚诞生?/p>

我记得毕业时候看那些公司的招聘广告,都是牛得不得了,恨不得把所有的条g都列上。英语要nU,要懂q个懂那个,什么c++,c,rup,oracle,sql server,linux,unix之类Q反正是能想到的东西都要懂,地球上存在地东西都要会。我当时看着那么多的招聘q告Q觉得自己没有几个能够得上h家的标准的。问问n边认识的人,好像也没有几个能够得上这L标准?/p>

其实我们当然知道Q这些都只是夸张而已。招聘的在招聘广告上掺水Q应聘的在简历上掺水。等到大家真的互怺解了Q对视嘿嘿一W,什么n多的技如云般飘散?/p>

只是我有时候真不知道,q样是好q是坏?/p>

]]>
վ֩ģ壺 ƷAVƬ߹ۿ| **һëƬ| þAV뾫Ʒɫҹ| þþþƷ2019ѹۿ| ޲122021鶹| պѿ| ƷѾþ| ޳߹ۿ| ձɫѹۿ| ȫӳѹۿ߿| ۺһ| ҹ18ѿ| ƷѾþ| ޾Ʒ˾þ| ۺƷ͵| þþþѿaԿ| պAVһ| Ļ޵һ| ĻӰԺ߲| þѾƷһ| պ Ļ| ˾þþƷҹ| Ƶۿ| гʮ·Ƶ| ĻسƷ޸| ޹Ʒþþò| ŮƵ77777| ¾þƵ| Ʒһþ| þҹɫƷAV | պŷһѹۿ| һƵ | ַ߹ۿ| ޳AƬ77777| ѹۿɫƵվbd| þùƷһ| ޳avƬwwwѼ| Av뾫Ʒ| ֳִִˬƵ| ɫƬѹۿ| һƵ߹ۿwww|