﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-The Spark of Thinking-文章分类-Talk</title><link>http://www.blogjava.net/sharkafeng/category/13282.html</link><description>Focus on Eclipse Tools.</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 20:24:47 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 20:24:47 GMT</pubDate><ttl>60</ttl><item><title>在你的企业级java应用中使用Drools(转)</title><link>http://www.blogjava.net/sharkafeng/articles/59454.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://www.blogjava.net/sharkafeng/articles/59454.html</guid><wfw:comment>http://www.blogjava.net/sharkafeng/comments/59454.html</wfw:comment><comments>http://www.blogjava.net/sharkafeng/articles/59454.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sharkafeng/comments/commentRss/59454.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sharkafeng/services/trackbacks/59454.html</trackback:ping><description><![CDATA[原文地址:<br /><a href="http://www.onjava.com/pub/a/onjava/2005/08/24/drools.html" target="_new">http://www.onjava.com/pub/a/onjava/2005/08/24/drools.html</a><br />中文地址:<br /><a href="http://www.matrix.org.cn/resource/article/43/43782_Drools.html" target="_new">http://www.matrix.org.cn/resource/article/43/43782_Drools.html</a><br />关键词： Drools J2ee<br /><br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">什么是Drools</span></b><br />(译者增加：什么是Drools, 摘自drools.org)<br />Drools 是一个基于Charles Forgy's的Rete算法的，专为Java语言所设计的规则引擎。Rete算法应用于面向对象的接口将使基于商业对象的商业规则的表达更为自然。Drools是用Java写的，但能同时运行在Java和.Net上。<br /><br /><b>Drools</b><br />Drools 被设计为可插入式的语言实现。目前规则能用Java, Python和Groovy实现。更为重要的是，Drools提供了声明式程序设计(Declarative Programming),并且使用域描述语言(Domain Specific Languages (DSL))－专为你的问题域定义了某种模式的Xml, 它已经足够灵活到可以用来描述你的问题域。DSLs包含的XML元素(Element)和属性(Attribute)代表了问题域中各种要素。<br /><br />(原文开始)<br />这段时间企业级Java简直能让你睡着。有多少J2EE-EJB应用程序只是从网页提取数据并把它们存入到数据库中?但开发者真正应该开发和维护的却是他们应用程序中复杂的商业逻辑。这个问题不仅仅适用于将要新应用，而且渐渐地，也适用于那些长期运行的商业核心应用，它们的内部逻辑也需要经常改变，而且往往要求在一个非常短的时间内。<br /><br />在以前的文章中，“用Drools让你的商业逻辑使用框架”,我介绍了Drools框架，展示了它如何用来组织复杂的商业逻辑。Drool用一组简单的，众所周知的事物替换了许多缠杂的if…then表达式。如果你经历过和商业客户的会议，并为他们提出的想要实现的东西的复杂程度搞得头痛，或许你应该考虑一下像Drools这样的规则引擎了。这篇文章将向你展示如何在企业级Java应用中使用Drools.<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">一路到底的框架</span></b><br /><br />大多数开发者都有自己喜爱的框架。无特定顺序，它们包括表现层框架（Struts, JSF, Cocoon和Spring）,持久化框架（JDO, Hibernate, Cayenne and Entity Beans）以及结构框架(EJB, 又是Spring, Pico和Excalibur), 还有其它很多。每种框架都各有所长，给开发者提供子许多“即开即用”的功能。使用框架来部署应用意味着你避免了许多让人厌烦的细节，让你集中注意力到关键之处。<br />到目前为直，在框架所能做的事中仍然有一个缺口，那就是商业逻辑没有框架。像EJB和Spring这样的工具虽好，但它们却几乎没有提及怎么组织你的那些if …then语句。把Drools加到你的开发工具箱中意味着现在你可以“一路到底”的使用框架来构建你的应用程序。图1显示了这样的一个应用<br /><br /><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/content/2005_09_19_001100_GUdrMLtFaq.gif" onload="javascript:imgLoad(this);" border="0" twffan="done" /><br />图1. 用于Java应用的框架<br /><br />这篇文章将基于我们已经了解的Drools框架的功能，这些功能可以让我们构建这样的一个应用。]<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">我什么时候应该使用规则引擎？</span></b><br />“如果你有一把锤子，那所有的东西都看起来都像钉子”，这句话在软件工程领域几乎成了陈词滥调了。虽然规则引擎能解决我们的许多问题，但确实值得认真考虑一下规则引擎对我们的企业级Java应用是否合适。需要问的问题有：<br /><br />● <b>我的应用程序有多复杂?</b>对于那些只是把数据从数据库中传入传出，并不做更多事情的应用程序，最好不要使用规则引擎。但是，当在Java中有一定量的商业逻辑处理的话，可以考虑Drools的使用。这是因为很多应用随着时间的推移越来越复杂，而Drools可以让你轻松应对这一切。<br /><br />● <b>我的应用的生命周期有多久？</b>这个问题的正确答案往往是“令人惊讶的长”――还记得那些认为他们的程序不会苟活到2000年的大型机的程序员吗？使用规则引擎将会在中长期得到好处。像这篇文章所展示的那样，甚至原型都能从Drools与灵活方法的组合中获益，让“原型系统”转化成生产系统。<br /><br />● <b>我的应用需要改变吗？</b>唯一能确定的是你的需求将会改变，无论是在开发过程中或是在开发完成以后。Drools使用一个或多个简单易配的XML文件帮你来应对这一切。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">那么性能呢？</span></b><br />如果你正在写一个企业级应用，很有可能它会扩展到成百（如果不是成千）的用户。你已经知道现有的Java和J2EE应用能做到这一点，但一个使用了Drools的应用对这一压力的表现如何？答案是：“令人吃惊的好”。大多数开发者只是因为不愿“失控”而依赖于他人的代码（比如：某种框架），想想这个：Drools不仅可以让你的应用和“传统”的编程方法一样快，甚至可以更快,看下面：<br /><br />● <b>避免糟糕的代码</b>：Drools引导开发者去做“正确的事”。你可以确定你正在写的代码是好的，但你的开发伙伴呢？你可以同样这样说吗？使用框架可以让你更轻松地写出更快，更好的代码。<br /><br />● <b>优化过的框架</b>：你有多少次看见商业逻辑重复地从数据库中提取相同的信息，从而降低了整个应用的速度？如果正确使用的话，Drools不仅仅能够记住信息，而且还能记住以往使用该信息进行测试的结果，从而大幅提升应用的速度。<br /><br />● <b>Rete算法</b>：很多次我们并不是真正需要使用“if”条件。被Drools实现的Rete算法，可以用一个优化的方法替换掉所有的“if…then”表达式。需要重点提及的是：Rete算法在使用更多的内存来降低运行时延迟方面作了折衷。当然这在现代的应用服务器中并不是一个问题，我们也并不推荐你在移动手机上使用Drools!<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">我们到哪里了？</span></b><br /><br />在我们上一篇文章中，我们写了一个基于Drools引擎的简单的股票交易程序。我们实现了不同的商业规则，展示了我们可以如何迅速地改变规则去适应商业需求，并且JUnit测试给了我们高度自信可以确认系统确实是像我们设想的那样运作的。但是这个应用几乎没有用户介面，而且用硬编码代替了数据库。为了把我们的程序提升到企业级的水平，我们需要增加两个主要的东西。<br /><br />● 某种用户介面，最理想的是基于标准的Web表现层的框架。<br />● 一个数据存取对象(DAO)让Drools与数据库（或其它后端）交互。<br /><br /><b>从现有表现框架中实现规则引擎</b><br /><br />大多数企业级Java应用是通过Web介面进行交互的，其中最被广泛使用的Web表现层框架是Apache的Struts。理想的结果是：我们写的应用可以从表现层知道它下面的应用层,而不是通过相反的方向。它的好处在于不仅仅可以使我们将来变换其它的表现层（比如Ajax或web service界面），而且意味着示例代码可以非常容易地应用于其它像Spring的框架。<br /><br />下面的代码片断演示了始何从Web表现层调用商业逻辑（通过规则引擎），并根据返回结果显示不同的页面。这一例子中，我们使用了一个Struts行为，但其代码是和使用其它表现层框架甚至一个Servlet或一个Jsp页面是很类似的。这个片断使用了struts-config.xml配置文件，JSP页面来上传/显示数据，并且生成WAR文件来进行布署。片断展示了怎样把规则引擎和web框架集成使用。<br /><br /><pre class="overflow">import javax.servlet.http.HttpServletRequest;<br />import javax.servlet.http.HttpServletResponse;<br />import org.apache.struts.action.Action;<br />import org.apache.struts.action.ActionForm;<br />import org.apache.struts.action.ActionForward;<br />import org.apache.struts.action.ActionMapping;<br />import BusinessLayer;<br />/**<br /> * Sample Struts action with Pseudocode<br /> * 使用伪代码的Struts行为示例<br /> */<br />public class SampleStrutsAction extends Action{<br />       <br />  /**<br />   * Standard Struts doPerfom method <br />   * 标准的Struts doPerform方法<br />   */<br />  public ActionForward doPerform(<br />                ActionMapping mapping,<br />                    ActionForm form,<br />                    HttpServletRequest request,<br />                    HttpServletResponse response)<br />        throws InvalidEntryPointException {<br />//Local Variables<br />//本地变量<br />    StockOffer userOffer =null;<br />        <br />//Get any previous values from the session<br />//从session取得以前的数据<br />    userOffer=(StockOffer)request.getSession()<br />           .getAttribute("PREVIOUS_STOCK_OFFER");<br />                <br />//create this object if it is null<br />//如为null则创建新对象<br />    if (null==userOffer){<br />      userOffer = new StockOffer();<br />    }<br />//Update with the incoming values <br />//用上送的数据更新<br />//These values match those on the form      <br />//这些数据是与form中的数据相对应的<br />    userOffer.setStockName(request.<br />                getParameterValue("STOCK_NAME"));<br />    userOffer.setStockPrice(request<br />               .getParameterValue("STOCK_PRICE"));<br />    userOffer.setStockQuantity(request<br />               .getParameterValue("STOCK_QTY"));<br />                                <br />//Reset the output value<br />//重置输出数据<br />    userOffer.setRecommendPurchase(null);<br />//Call the Business Layer<br />//调用商业层<br />    BusinessLayer<br />              .evaluateStockPurchase(userOffer);        <br />                <br />//Forward to the appropriate page <br />//转向合适的页面<br />    if ("YES".equals(<br />      testOffer.getRecommendPurchase()){<br />        return mapping.findForward("YES_WEB_PAGE");<br />    } <br />//otherwise default to the no page<br />//否则指向无此页面<br />          return mapping.findForward("NO_WEB_PAGE");<br />  }<br />}</pre><br /><br />这个例子包含了几个东西。经常，我们需要的数据是用户通过好几个网页传来的，因此在这一例子中展示了通过session中的StockOffer对象来保存过去以来的数据。<br /><br />下一步，如果用户改变了一些值，我们更新StockOffer对象。然后我们重置了rcommendPurchase标志用以在调用商业逻辑层之前清除以前的结果。最后我们使用商业逻辑层的返回来决定让用户转向哪一页面。<br /><br />在这一例子中，需要注意我们将商业逻辑（买或不买一支股票）与表现层逻辑（决定转向哪一页面）分离开来。这将使我们可以在不同的应用中重用我们的商业规则。另外，看一下状态信息（用户已经告知我们的东西）是存储在Session中的StockOffer对象中的，并没有在商业层中。这样就保证了商业层的无状态性，这将使整个应用更具扩展性和性能。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">集成规则引擎与数据库层</span></b><br /><br />到目前为止，我们的应用已经有一个web表现层和一个商业层的规则引擎，但还没有方法与数据库进行交互。这一节的例子将展示如何实现。我们的例子是基于数据访问对象（DAO）模式的，它把所有与数据库（或后端数据源）交互的代码包装在了一个可插入，可配置的类中。同样的，这一例子一样适用于其它持久性框　架，比如Hibernate和Cayenne。<br />关于如何组织数据导有几个要点：<br /><br />● 应该只有商业层与数据层交互。如果表现层（前端）需要一些数据，它首先应通过商业层。这将使我们的代码更容易组织和阅读。<br />● 尽可能地，我们应让我们的数据层无状态－我们应该在其它的地方存放客户端数据（比如：web前端的session，就像前面的例子）。这不同于我们可以在这一层做的数据缓存。两者的区别在于状态信息经常是用户定义的，而我们在数据层缓存的数据应该是整个应用共享的。这样的层次提升了性能。<br />● 我们应该让商业逻辑决定数据是否需要――如不需要，提取数据的调用就不应该执行。<br /><br />为了实现我们简单的数据访问对象，我们创建三个新对象：StockNameDao, DaoImplementation,和 DaoFactory<br /><br />StockNameDao是一个定义了两个方法的接口：getStockName()返回一个我们可以处理的股票名称的列表,isOnStockList()检查一个给定的股票是否在处理列表中。我们的商业层在需要这些信息时会调用这些方法。<br /><br />DaoImplementation是StockNameDao的一个实现。这里的数据是硬编码的，但我们可以通过查询数据库或通过像Bloomberg这样的web service提取信息。<br /><br />DaoFactory我们用来生成合适的StockNameDao实例。不直接创建对象而使用这一小骤的好处在于，它充许我们在运行时刻决定使用哪一个DAO实现（这是像Spring这样的框架特别擅长的）.一个factory（工厂）可以返回多种类型的DAO(比如：StockNameDao, StockPriceDao, StockHistoryDao),这意味着我们可以通过我们的DaoFactory,让规则自己决定需要什么数据和DAO.<br /><br />这是StockNameDao接口：<br /><br /><pre class="overflow">/**<br /> * Defines a Data Access Object - a non data <br /> * source specific way of obtaining data.<br /> * 定义一个数据存取对象－一种非数据源获取数据的方法<br /> */ <br />public interface StockNameDao {<br />  /**<br />   * Get a list of stock names for the application <br />   * @return String[] array of stock names<br />   * 得到一个股票名字的列表<br />   * 返回股票名称的String[]数组<br />   */<br />  public String [] getStockNames();<br />        <br />  /**<br />   * Check if our stock is on the list<br />   * 检查股票是否在列表中<br />   * @param stockName<br />   * @return<br />   */<br />  public boolean isOnStockList(String stockName);<br />}<br />And here's the DaoImplementation:<br />这是DaoImplementation:<br /><br />/**<br /> * Concrete Definition of a Data Access Object <br /> * 数据存取对象的具体定义<br /> */ <br />public class DaoImplementation<br />                        implements StockNameDao {<br />  /**<br />   * Constructor with package level access only <br />   * to encourage use of factory method<br />   * 这里的构造器只是让你使用工厂(factory)方法<br />   */<br />  DaoImplementation(){}<br />  /**<br />   * Get a list of stock names for the app.<br />   * This is a hard coded sample <br />   * normally we would get this from<br />   * a database or other datasource.<br />   * 得到一个股票名字的列表，这只是一个硬编码的例子，一般来<br />　 * 说我们应该从数据库或其它数据源取得数据<br />   * @return String[] array of stock names<br />   */<br />  public String[] getStockNames() {<br />    String[] stockNames=<br />      {"XYZ","ABC","MEGACORP","SOMEOTHERCOMPANY"};<br />  <br />    return stockNames;<br />  }<br />        <br />  /**<br />   * Check if our stock is on the list <br />   * 检查我们的股票是否在列表中<br />   * @param stockName<br />   * @return true / false as appropriate<br />   */<br />  public boolean isOnStockList(String stockName){<br />                <br />//Get our list of stocks  <br />//获取股票列表          <br />    String stockList[] = getStockNames();<br />                <br />    //Loop and see if our stock is on it<br />// done this way for clarity . not speed!<br />//循环看股票是否存在，这样做是为了清晰不是速度!<br />    for (int a=0; a&lt;stockList.length;a++){<br />        if(stockList[a].equals(stockName)){<br />          return true;<br />        }<br />    }<br />                <br />    //Default return value<br />    return false;       <br />  }<br />}</pre><br /><br />简单的DaoFactory,只是返回DaoImplementation：<br /><br /><pre class="overflow">package net.firstpartners.rp;<br />/**<br /> * Factory Method to get the Data Access Object.<br /> * Normally we could replace this with a <br /> * framework like Spring or Hibernate <br /> * 得到数据存取对象的工厂方法，通常我们可以将它替换为像Spring或<br />*  Hibernatte这样的框架<br /> */<br />public class DaoFactory {<br />  /**<br />   * Get the stock name Dao<br />   * This sample is hardcoded - in reality <br />   * we would make this configurable / cache<br />   * instances of the Dao as appropriate<br />   * 得到股票名字的Dao,这个例子是硬编码的－实际上我们可以让它成为<br />　 * 可配的，缓存的合适的Dao对象。<br />   * @return an instance of StockNameDao<br />   */<br />  public static StockNameDao getStockDao(){<br />        return new DaoImplementation();<br />  }<br />}</pre><br /><br />现在我们有了简单的DAO实现来作为我们的数据库层，那如何将它与Drools商业层集成在一起呢？最新的商业规则文件，BusinessLayer.xml将会向我们展示：<br /><br /><pre class="overflow">&lt;?xml version="1.0"?&gt;<br />&lt;rule-set name="BusinessRulesSample"<br />  xmlns="http://drools.org/rules"<br />  xmlns:java="http://drools.org/semantics/java"<br />  xmlns:xs="<br />        http://www.w3.org/2001/XMLSchema-instance"<br />  xs:schemaLocation="<br />        http://drools.org/rules rules.xsd<br />  http://drools.org/semantics/java java.xsd"&gt;<br />  &lt;!-- Import the Java Objects that <br />                        we refer to in our rules --&gt; <br />&lt;!-- 导入规则中使用的对象 --&gt;<br />  &lt;java:import&gt;<br />    java.lang.Object<br />  &lt;/java:import&gt;<br />  &lt;java:import&gt;<br />    java.lang.String<br />  &lt;/java:import&gt;<br />  &lt;java:import&gt;<br />    net.firstpartners.rp.StockOffer<br />  &lt;/java:import&gt;<br />  &lt;java:import&gt;<br />    net.firstpartners.rp.DaoFactory<br />  &lt;/java:import&gt;<br />  &lt;java:import&gt;<br />    net.firstpartners.rp.StockNameDao<br />  &lt;/java:import&gt;<br />  &lt;!-- Application Data not associated --&gt;<br />  &lt;!-- with any particular rule --&gt;<br />  &lt;!-- In this case it's our factory --&gt;<br />  &lt;!-- object which gives us back --&gt;<br />  &lt;!-- a handle to whatever Dao (Data --&gt;<br />  &lt;!-- access object) that we need --&gt;<br />  &lt;!-- 没有和任何规则联系的应用数据，这里是我们的工厂对象，--&gt;<br />  &lt;!—它向我们提供向后的操作,告诉我们什么Dao 是我们需要的。--&gt;<br /><br />  &lt;application-data <br />    identifier="daoFactory"&gt;DaoFactory<br />  &lt;/application-data&gt;<br />  &lt;!-- A Java (Utility) function --&gt;<br /> &lt;!-- 一个Java方法 --&gt;<br />  &lt;!-- we reference in our rules --&gt;   <br />  &lt;!-- 在我们的规则中打印跟踪信息 --&gt;    <br />  &lt;java:functions&gt;<br />    public void printStock(<br />      net.firstpartners.rp.StockOffer stock)<br />      {<br />          System.out.println(<br />          "Name:"+stock.getStockName()<br />          +" Price: "+stock.getStockPrice()     <br />          +" BUY:"+stock.getRecommendPurchase());<br />      } <br />  &lt;/java:functions&gt;<br />  &lt;!-- Check for XYZ Corp--&gt;   <br />&lt;!-- 检查XYZ公司 --&gt;    <br />  &lt;rule name="XYZCorp" salience="-1"&gt;<br />    &lt;!-- Parameters we can pass into--&gt; <br />&lt;!-- the business rule --&gt;<br />&lt;!-- 可以传入规则中的参数 --&gt;<br />    &lt;parameter identifier="stockOffer"&gt;<br />      &lt;class&gt;StockOffer&lt;/class&gt;<br />    &lt;/parameter"&gt;<br />    &lt;!-- Conditions that must be met for --&gt;<br />&lt;!-- business rule to fire --&gt;   <br />&lt;!-- 激活规则必须满足的条件 --&gt;      <br />    &lt;java:condition&gt;<br />      stockOffer.getStockName().equals("XYZ")<br />    &lt;/java:condition&gt; <br />    &lt;java:condition&gt;<br />      stockOffer.getRecommendPurchase() == null<br />    &lt;/java:condition&gt;<br />    &lt;java:condition&gt;<br />      stockOffer.getStockPrice() &gt; 10<br />    &lt;/java:condition&gt;<br />        <br />    &lt;!-- What happens when the business --&gt;<br />&lt;!-- rule is activated --&gt;<br />&lt;!-- 规则激活后执行的步骤 --&gt;<br />    &lt;java:consequence&gt;<br />        stockOffer.setRecommendPurchase(<br />        StockOffer.NO); <br />        printStock(stockOffer);<br />    &lt;/java:consequence&gt;<br />  &lt;/rule&gt;<br />  &lt;!-- Ensure that negative prices --&gt;<br />  &lt;!-- are not accepted --&gt;  <br />  &lt;!-- 确定负数不被接受 --&gt;     <br />  &lt;rule name="Stock Price Not Negative"&gt;<br />    &lt;!-- Parameters we can pass into the --&gt;<br />&lt;!-- business rule --&gt;<br />&lt;!-- 可以传入规则中的参数 --&gt;   <br />    &lt;parameter identifier="stockOffer"&gt;<br />      &lt;class&gt;StockOffer&lt;/class&gt;<br />    &lt;/parameter&gt;<br />&lt;!-- Conditions for rule to fire --&gt;<br />&lt;!-- 激活规则必须满足的条件 --&gt;    <br />    &lt;java:condition&gt;<br />      stockOffer.getStockPrice() &lt; 0<br />    &lt;/java:condition&gt;<br />  <br />&lt;!--When rule is activated then ... --&gt;<br />&lt;!-- 规则激活后执行的步骤 --&gt;<br />    &lt;java:consequence&gt;<br />      stockOffer.setRecommendPurchase<br />        (StockOffer.NO);        <br />      printStock(stockOffer);<br />    &lt;/java:consequence&gt;<br />  &lt;/rule&gt;<br />  &lt;!-- Check for Negative Prices--&gt;   <br />&lt;!-- 寻找低价 --&gt;     <br />  &lt;rule name="Stock Price Low Enough"&gt;<br />  &lt;!-- Parameters for the rule --&gt;<br />&lt;!-- 可以传入规则中的参数 --&gt;<br />    &lt;parameter identifier="stockOffer"&gt;<br />      &lt;class&gt;StockOffer&lt;/class&gt;<br />    &lt;/parameter&gt;<br />    <br />&lt;!-- Now uses Dao to get stock list --&gt;<br />&lt;!-- 现在使用Dao获取股票列表 --&gt;<br />    &lt;java:condition&gt;<br />      daoFactory.getStockDao().isOnStockList(<br />        stockOffer.getStockName())<br />    &lt;/java:condition&gt;<br />        <br />    &lt;java:condition&gt;<br />      stockOffer.getRecommendPurchase() == null<br />    &lt;/java:condition&gt;<br />    &lt;java:condition&gt;<br />      stockOffer.getStockPrice() &lt; 100<br />    &lt;/java:condition&gt;<br />&lt;!-- When rule is activated do this --&gt;<br />&lt;!-- 规则激活后执行的步骤 --&gt;<br />    &lt;java:consequence&gt;<br />        stockOffer.setRecommendPurchase(<br />          StockOffer.YES);      <br />          printStock(stockOffer);<br />    &lt;/java:consequence&gt;<br />  &lt;/rule&gt;<br />&lt;/rule-set&gt;</pre><br /><br />为了与数据访问层集成，该文件(相对于上一篇文章)有几处改变：<br />● 在最上面，我们有几个新的&lt;java:import&gt;来把StockNameDao, DaoImplementation, 和 DaoFactory类引入系统。<br />● 我们有一个新的标记&lt;application-data&gt;,它把DaoFactory的实例赋给一个变量。&lt;application-data&gt;标记类似于参数，只不过它是运用于所有商业规则，而不只是一个。<br />● “股价足够低”的规则有一个新条件，它用DaoFactory和StockNameDao来检查股票是否在处理列表中。<br /><br />我们又一次运行BusinessRulesTest(模拟器)。模拟单元测试没有问题，既使我们改变了程序的结构，我们仍然没有改变它在做什么。从输出的日志来看，我们可以看到我们的商业规则使用StockNameDao作为他们评估的一部份，并且DaoImplementation.isOnStockList()被调用了。<br />虽然这个例子展示的是从数据源读取信息，其实写信息也是一样的原理。如果某个规则决定应该做的话。区别在于我们的DAO将会有一些setSomeInformation()的方法，一旦条件满足，这个方法将会在商业规则的&lt;java:consequence&gt;部分被调用。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">总结</span></b><br />这篇文章中，我们展示了大多数Java服务器端的应用有的三层：表现层，商业逻辑层和数据持久化层。当框架被广泛地使用在表现层和持久层中，直到目前为止还没有框架可以包装低级的商业逻辑。就像我们在这些例子中看的，Drools和JSR-94是降低java应用复杂度，提高开发速度的理想候选者。我希望这些例程能鼓励你去进一步接近规则引擎，他们将会为你的应用的开发和维护节省不少时间。<br />资源<br />● <a href="http://sourceforge.net/project/showfiles.php?group_id=99476&amp;package_id=158438" target="_new">本文的范例代码</a><br />● <a href="http://www.drools.org/" target="_new">Drools项目主页</a><br />● [ur=http://www.jroller.com/page/eu/20040810]Drools规则的信息[/url] <br />● <a href="http://www.theserverside.com/articles/article.tss?l=Drools" target="_new">"Introduction to Drools and Rule Engines," Drools项目组提供</a><br />● <a href="http://www.geocities.com/CapitolHill/5910/drltk/instructions.htm" target="_new">Drools规则的schema文件</a><br />● <a href="http://javaboutique.internet.com/tutorials/rules_engine/" target="_new">JSR-94: Java规则引擎概述</a><br />● <a href="http://struts.apache.org/" target="_new">Struts框架主页</a><br />● <a href="http://www.springframework.org/" target="_new">Spring框架主页</a><br />● <a href="http://www.hibernate.org/" target="_new">Hibernate主页</a><br />● <a href="http://www.junit.org/" target="_new">JUnit测试框架</a><br />● <a href="http://www.matrix.org.cn/resource/article/43/]Jess%20Java规则引擎[/url" target="_new"><br />● [url=http://herzberg.ca.sandia.gov/jess/index.shtml]Jena语义与规则引擎</a><br />● <a href="http://jcp.org/aboutJava/communityprocess/review/jsr094/" target="_new">JSR-94主页</a><br />● <a href="http://www.manning.com/friedman-hill" target="_new">Jess in Action主页</a><br />● <a href="http://herzberg.ca.sandia.gov/jess/zen.shtml" target="_new">"Business Rule Thinking" (基于Jess) </a><br />●<a href="http://www.aaai.org/AITopics/html/expert.html" target="_new">规则系统的概述</a><br />● <a href="http://herzberg.ca.sandia.gov/jess/docs/61/rete.html" target="_new">"Jess implementation of the Rete algorithm" </a><br /><br />Paul Browne 已经为 FirstPartners.net在企业级Java应用方面作了差不多7年的顾问 <br /><img src ="http://www.blogjava.net/sharkafeng/aggbug/59454.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sharkafeng/" target="_blank">The Spark of Thinking</a> 2006-07-21 16:59 <a href="http://www.blogjava.net/sharkafeng/articles/59454.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>准备放弃struts,因为它是一个拙劣的设计！</title><link>http://www.blogjava.net/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://www.blogjava.net/sharkafeng/articles/59455.html</guid><wfw:comment>http://www.blogjava.net/sharkafeng/comments/59455.html</wfw:comment><comments>http://www.blogjava.net/sharkafeng/articles/59455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sharkafeng/comments/commentRss/59455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sharkafeng/services/trackbacks/59455.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 看看别人的总结：前4个缺点是致命的，																																																												Action																								类																																																在								...&nbsp;&nbsp;<a href='http://www.blogjava.net/sharkafeng/articles/59455.html'>阅读全文</a><img src ="http://www.blogjava.net/sharkafeng/aggbug/59455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sharkafeng/" target="_blank">The Spark of Thinking</a> 2006-07-21 16:59 <a href="http://www.blogjava.net/sharkafeng/articles/59455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Drools- 商务逻辑框架的选择</title><link>http://www.blogjava.net/sharkafeng/articles/59453.html</link><dc:creator>The Spark of Thinking</dc:creator><author>The Spark of Thinking</author><pubDate>Fri, 21 Jul 2006 08:58:00 GMT</pubDate><guid>http://www.blogjava.net/sharkafeng/articles/59453.html</guid><wfw:comment>http://www.blogjava.net/sharkafeng/comments/59453.html</wfw:comment><comments>http://www.blogjava.net/sharkafeng/articles/59453.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sharkafeng/comments/commentRss/59453.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sharkafeng/services/trackbacks/59453.html</trackback:ping><description><![CDATA[作者:保罗.布朗;<a href="http://www.matrix.org.cn/user.shtml?username=greenbright" target="_new">greenbright</a><br />原文地址:<a href="http://www.onjava.com/pub/a/onjava/2005/08/03/drools.html" target="_new">http://www.onjava.com/pub/a/onjava/2005/08/03/drools.html</a><br />中文地址:<a href="http://www.matrix.org.cn/resource/article/44/44046_Drools+Framework+Business.html" target="_new">http://www.matrix.org.cn/resource/article/44/44046_Drools+Framework+Business.html</a><br />关键词： Drools Framework Business<br /><br /><br />大多数网络及企业级Jave应用可以分为三部分：和用户交互的前端，和后端系统（比如数据库）交互的服务层和这两部分之间的商务逻辑层。通常使用框架（像Struts, Cocoon, Spring, Hibernate, JDO, 和实体Beans）可以实现前端和后端的功能，但对于商务逻辑层却没有一个标准的构建方法。像EJB和Spring只能在高端实现商务逻辑构建，但却不能组织代码。如果我们使用在配置性，可读性和重用性方面带我们极大利益的框架代替那些纷繁复杂的if...then语句，那不是很好吗？在其他领域我们已经验证了这种利益。这篇文章建议使用<a href="http://www.drools.org/" target="_new">Drools规则引擎</a>作为框架来解决问题。<br /><br />下面的代码是我们试图避免的问题的例子。说明一个典型Java应用中的一些商务逻辑。<br /><pre class="overflow">if ((user.isMemberOf(AdministratorGroup)<br />      &amp;&amp; user.isMemberOf(teleworkerGroup))<br />     || user.isSuperUser(){      <br />         // 更多对特殊案例的检查<br />         if((expenseRequest.code().equals("B203")<br />           ||(expenseRequest.code().equals("A903")<br />                        &amp;&amp;(totalExpenses&lt;200)<br />                &amp;&amp;(bossSignOff&gt; totalExpenses))<br />           &amp;&amp;(deptBudget.notExceeded)) {<br />               //付款<br />           } else if {<br />               //检查许多其他的条件<br />           }<br />} else {<br />     //更多商务逻辑<br />}</pre><br /><br />我们都曾经历过相类似或者更为复杂的商务逻辑。当试图在Java中采用标准方法来实施商务逻辑时，就有很多问题随之而来。<br />·        如果商务人员提出需要在本已很难理解的代码中加入另外一个表单（"C987"）怎么办？一旦所有的最初开发人员都在开发中，你愿意成为一个维护人员吗？<br />·        如何确认这些规则的正确与否？对技术人员来说（从来不关注商务人员），检查规则的正确性是非常困难的。那么，有什么方法论来测试商务逻辑那？<br />许多应用有着类似的商务逻辑。如果其中一个规则发生了变化，我们能够确认所有系统中的相关部分都要改变吗？如果一个新应用使用了一些规则，但是也加入了一些新规则，我们需要彻底重写逻辑吗？ <br />·        商务逻辑嵌入在Java代码中，每次哪怕是很小的改变都需要再编译/再部署这些代码，这些商务逻辑容易配置吗?<br />·        如果其他的（脚本）语言想平衡现有投资在商务规则逻辑中怎么办？<br /><br />J2EE/EJB和倒置控制的框架（像Spring, Pico和Avalon）让我们有能力在高端组织代码。他们很提供很好的重用性，配置性和安全性，但却不能替代上面例子中的<a href="http://en.wikipedia.org/wiki/Spaghetti_code" target="_new">“意大利面条式代码”</a>。理想地，无论我们选择那个框架，不仅要和J2EE应用，而且要和通常Java编程(J2SE—标准版本)及广泛使用的表现和持续性框架相一致。这种框架让我们能够做到：<br />·        商务用户很容易的读和验证商务逻辑。<br />·        在应用中，商务规则是可重用的和可配置的。<br />·        在重负荷下，框架是可扩展的和性能良好的。<br />·        Java编程人员对已存在的前端（Struts, Spring）和后端框架（对象关系映射）很容易使用这种框架。<br /><br />另一个问题是在不同的应用中，组织页面，数据库访问和商务逻辑的方法也是多种多样的。我们的框架能够处理这个问题，并能始终提升代码的重用性。理想地，我们的应用使用“适用所有方式的框架”。以这种方式使用框架，能够让我们许多的应用构建的更好，让我们可以仅关注那些对用户更有价值的部分。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">规则引擎的营救</span></b><br /><br />如何解决这个问题那? 一个解决方案是使用规则引擎。规则引擎是组织商务逻辑的框架。它让开发者集中精力在他们有把握的事情上，而不是在一些低级机制上作决定。<br />通常，商务用户对那些能让他们理解是正确的事情感到更加舒服，相对于那些诸如用<span style="COLOR: blue" twffan="done">if...then </span>形式来表达的事情。你从商务专家那里听到的一些事情如下<br />·        “10A表单用于申请超过200欧元的花费.”<br />·        “我们仅对数量1万或超过1万的交易提供分成.”<br />·        “超过10m英镑的采购需要公司总监的批准.”<br /><br />通过关注于商务用户知道是正确的事情上，而不是怎样用Jave代码来表达它，上面的说明比以前我们的代码例子要清楚的多。尽管他们已经很清楚了，我们仍然需要一种机制，将这些规则应用到商务用户已知和作决定的事实中去。这种机制就是规则引擎。<br /><br /><span style="COLOR: red" twffan="done">相关文章：</span><br /><a href="http://www.matrix.org.cn/resource/article/43/43782_Drools.html" target="_new">在企业级Java应用中使用Drools</a><br />企业级Java应用开发者在表现和持续层有很多好的框架可供选择。但对于处在中间层的商务逻辑有好的框架吗？你希望每次经理给你一个新的命令就不得不重编译那些复杂的if ... then 意大利面条代码吗？这篇文章中，保罗布朗推荐的Drools的规则引擎或许是完成这类任务的最好选择。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">Jave规则引擎</span></b><br /><br /><a href="http://javaboutique.internet.com/tutorials/rules_engine/" target="_new">JSR 94</a>- javax.rules API制定了与规则引擎交互的通用标准，就像JDBC能够与各种类型的数据库交互。JSR-94并不是详细说明实际规则到底是怎么写的，而是最大限度的使用Java规则引擎来做这种详细说明。<br />·        Jess可能是最成熟的Java规则引擎，有很多好的工具（包括Eclipse）和文档。然而它是一个商业产品，并且它的规则是以序言样式符号写的，这对许多Java编程者都是一个挑战。<br />·        Jena是开源框架，始于HP.它有规则引擎，并且对那些关注于语义的网页特别支持。但它并不完全遵守JSR-94。<br />·        Drools是完全遵守JSR-94的规则引擎。而且是Apache模式许可下的完全开源框架。它不仅用大家熟知的Java 和XML语法来表示规则，而且有很强的用户和开发者团体。本文章中的例子中，我们将使用Drools。Drools使用像Java的语法，并且有最开放的许可。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">用Drools开始开发Java应用</span></b><br /><br />想象一下这种情景：就在读了这篇文章几分钟后，你的老板让你给股票交易应用建原型。尽管商务用户还没有定义好商务逻辑，一个可以想到的好主意就是用规则引擎来实现。最终的系统将通过网络访问，并且需要和后端数据库和信息系统交流。为了开始使用这个框架，需要下载Drools框架（有依赖性）。如图1所示，在你喜欢的IDE中建一个新项目并确保所有的.jars文件都被引用了。<br /><br /><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/forum/2005_12_12_230601_HHjSitMOHT.gif" onload="javascript:imgLoad(this);" border="0" twffan="done" /><br />图1。运行Drools必需的类库<br /><br />由于潜在可能的巨大损失，如果我们的股票交易系统想要成功，在系统中循序渐进的使用一系列模拟器就显得很重要。这样的模拟器能够让你确信，即使规则改变了，由系统的作的决定也是正确的。我们将借用灵活工具箱的一些工具，并用JUnit框架作为模拟器。<br /><br />如下例所示，我们所写的第一段代码是Junit测试/模拟器。尽管我们不能测试所有输入系统的值的组合，由测试总比什么都不测好。在这个例子中，所有的文档和classes（包括单元测试）又在一个文件夹/包中；但事实上，由应该创建合适的包和文件夹结构。在代码中，我们用Log4j代替System.out调用。<br /><br /><b>清单1:</b><br /><pre class="overflow">import junit.framework.TestCase;<br />/*<br /> * 应用中商务规则的JUnit测试<br />        * 这也扮演商务规则的“模拟器“-让我们说明输入，检验输出；并在代码发*布前看看是否达到我的期望值。<br />*/<br />public class BusinessRuleTest extends TestCase {<br />/**<br />*股票购买测试<br />*/<br />  public void testStockBuy() throws Exception{<br />                <br />//用模拟值创建股票<br />    StockOffer testOffer = new StockOffer();<br />    testOffer.setStockName("MEGACORP");<br />    testOffer.setStockPrice(22);<br />    testOffer.setStockQuantity(1000);<br />                <br />//运行规则<br />    BusinessLayer.evaluateStockPurchase(testOffer);<br />                <br />        //达到我们的期望吗？<br />    assertTrue(<br />      testOffer.getRecommendPurchase()!=null);<br />    <br />    assertTrue("YES".equals(<br />      testOffer.getRecommendPurchase()));               <br />   }<br />}</pre><br /><br />这是个基本Junit测试，我们知道这个简单系统应该买进所有价格低于100欧元的股票。很显然，没有数据类（StockOffer.java）和商务层类（BusinessLayer.java）这个测试用例是不能编译成功的。<br /><br /><b>清单2:</b><br /><pre class="overflow">/**<br />*示例商务逻辑的正面<br />*这个简单示例里，所有的商务逻辑都包含在一个类中。<br />*但在现实中，按需要代理给其他的类。<br />*/<br />public class BusinessLayer {<br /><br />        /**<br />   *评价购买这支股票是否是个好主意<br />   *@参数 stockToBuy<br />   *@return 如果推荐购买股票返回真，否则返回假<br />   */<br />  public static void evaluateStockPurchase<br />    (StockOffer stockToBuy){<br />                return false;<br />  }<br />}<br />StockOffer类如下所示：<br />/**<br />* 简单的JavaBean保存StockOffer值。<br />* 一个’股票出价’就是别人卖出股票（公司股份）所给出的价格。<br />*/<br />public class StockOffer {<br />        <br />  //常量<br />  public final static String YES="YES";<br />  public final static String NO="NO";<br /><br />  //内部变量<br />  private String stockName =null;<br />  private int stockPrice=0;<br />  private int stockQuantity=0;<br />  private String recommendPurchase = null;<br /><br />/**<br />   * @返回股票名称<br />   */<br /><br />  public String getStockName() {<br />        return stockName;<br />  }<br />/**<br />   * @参数 stockName 设置股票名称.<br />   */<br />  public void setStockName(String stockName) {<br />        this.stockName = stockName;<br />  }<br />/**<br />   * @return 返回股票价格.<br />   */<br /><br />  public int getStockPrice() {<br />        return stockPrice;<br />  }<br />/**<br />   * @参数 stockPrice设置股票价格.<br />   */<br /><br />  public void setStockPrice(int stockPrice) {<br />        this.stockPrice = stockPrice;<br />  }<br />/**<br />   * @return 返回股票数量.<br />   */<br /><br />  public int getStockQuantity() {<br />        return stockQuantity;<br />  }<br />/**<br />   * @参数 stockQuantity 设置股票数量.<br />   */<br /><br />  public void setStockQuantity(int stockQuantity){<br />        this.stockQuantity = stockQuantity;<br />  }<br />/**<br />   * @return 返回建议购买.<br />   */<br /><br />  public String getRecommendPurchase() {<br />        return recommendPurchase;<br />  }<br />}</pre><br /><br />在我们熟悉的IDE的Junit中运行BusinessRuleTest。如果你不太熟悉Junit，可以从Junit网站获取更多信息。如图2所示，毫不奇怪的是，由于没有准备好适当的商务逻辑，测试在第二个申明处失败了。这个确信了模拟器/单元测试重点加强了他们应该有的问题。<br /><br /><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/forum/2005_12_12_230733_CsZnSMdDeO.gif" onload="javascript:imgLoad(this);" border="0" twffan="done" /><br />图2。Junit测试结果<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">用规则描述商务逻辑</span></b><br /><br />现在，我们需要描述一些商务逻辑，像“如果股票价格低于100欧元，应该购买。”<br />这样我们将修改BusinessLayer.java为：<br /><br /><b>清单3:</b><br /><pre class="overflow">import java.io.IOException;<br />import org.drools.DroolsException;<br />import org.drools.RuleBase;<br />import org.drools.WorkingMemory;<br />import org.drools.event.DebugWorkingMemoryEventListener;<br />import org.drools.io.RuleBaseLoader;<br />import org.xml.sax.SAXException;<br />/**<br />*示例商务逻辑的正面<br />*这个简单示例里，所有的商务逻辑都包含在一个类中。<br />*但在现实中，按需要代理给其他的类。<br />*@作者 缺省<br />*/<br />public class BusinessLayer {<br />//包含规则文件的名字<br />  private static final String BUSINESS_RULE_FILE=<br />                              "BusinessRules.drl";<br />        //内部处理的规则基础<br />  private static RuleBase businessRules = null;<br />/**<br />* 如果还没有装载商务规则的话就装载它。<br />*@抛出异常 -通常从这里恢复<br />*/<br />  private static void loadRules()<br />                       throws Exception{<br />    if (businessRules==null){<br />      businessRules = RuleBaseLoader.loadFromUrl(<br />          BusinessLayer.class.getResource(<br />          BUSINESS_RULE_FILE ) );<br />    }<br />  }     <br />        <br />/**<br />   *评价是否购买这支股票<br />   *@参数 stockToBuy<br />   *@return 如果推荐购买股票返回真，否则返回假<br />   *@抛出异常<br />   */<br />  public static void evaluateStockPurchase<br />       (StockOffer stockToBuy) throws Exception{<br />                <br />//确保商务规则被装载<br />    loadRules();<br />//一些程序进行的日志<br />    System.out.println( "FIRE RULES" );<br />    System.out.println( "----------" );<br />        //了解以前运行的状态<br />    WorkingMemory workingMemory <br />            = businessRules.newWorkingMemory();<br />//小规则集可以添加调试侦听器<br />    workingMemory.addEventListener(<br />      new DebugWorkingMemoryEventListener());<br />        //让规则引擎了解实情<br />    workingMemory.assertObject(stockToBuy);<br />        //让规则引擎工作<br />    workingMemory.fireAllRules();<br />  }<br />}</pre><br /><br />这个类有许多重要的方法：<br />·        loadRules()方法装载BusinessRules.drl文件中的规则。<br />·        更新的evaluateStockPurchase()方法评价这些商务规则。这个方法中需要注意的是：<br />·        同一个RuleSet可以被重复使用（内存中的商务规则是无状态的）。<br />·        由于以我们的知识我们知道什么是正确的，每次评价我们使用一个新的WorkingMemory类。在内存中用assertObject()方法存放已知的实事（作为Java对象）。<br />·        Drools有一个事件侦听模式，能让我们“看到“事件模式内到底发生了什么事情。在这里我们用它打印出调试信息。Working memory类的fireAllRules()方法让规则被评价和更新（在这个例子中，stock offer）。<br /><br />再次运行例子之前，我们需要创建如下BusinessRules.drl文件：<br /><br /><b>清单4:</b><br /><pre class="overflow">&lt;?xml version="1.0"?&gt;<br />&lt;rule-set name="BusinessRulesSample"<br />  xmlns="http://drools.org/rules"<br />  xmlns:java="http://drools.org/semantics/java"<br />  xmlns:xs<br />    ="http://www.w3.org/2001/XMLSchema-instance"<br />  xs:schemaLocation<br />    ="http://drools.org/rules rules.xsd<br />  http://drools.org/semantics/java java.xsd"&gt;<br />  &lt;!-- Import the Java Objects that we refer <br />                          to in our rules --&gt;        <br />  &lt;java:import&gt;<br />    java.lang.Object<br />  &lt;/java:import&gt;<br />  &lt;java:import&gt;<br />    java.lang.String<br />  &lt;/java:import&gt;<br />  &lt;java:import&gt;<br />    net.firstpartners.rp.StockOffer<br />  &lt;/java:import&gt;<br />  &lt;!-- A Java (Utility) function we reference <br />    in our rules--&gt;  <br />  &lt;java:functions&gt;<br />    public void printStock(<br />      net.firstpartners.rp.StockOffer stock)<br />        {<br />        System.out.println("Name:"<br />          +stock.getStockName()<br />          +" Price: "+stock.getStockPrice()     <br />          +" BUY:"<br />          +stock.getRecommendPurchase());<br />        }<br />  &lt;/java:functions&gt;<br />&lt;rule-set&gt;<br />  &lt;!-- Ensure stock price is not too high--&gt;      <br />  &lt;rule name="Stock Price Low Enough"&gt;<br />    &lt;!-- Params to pass to business rule --&gt;<br />    &lt;parameter identifier="stockOffer"&gt;<br />      &lt;class&gt;StockOffer&lt;/class&gt;<br />    &lt;/parameter&gt;<br />    &lt;!-- Conditions or 'Left Hand Side' <br />        (LHS) that must be met for <br />         business rule to fire --&gt;<br />    &lt;!-- note markup --&gt;<br />    &lt;java:condition&gt;<br />      stockOffer.getRecommendPurchase() == null<br />    &lt;/java:condition&gt;<br />    &lt;java:condition&gt;<br />      stockOffer.getStockPrice() &lt; 100<br />    &lt;/java:condition&gt;<br />    &lt;!-- What happens when the business <br />                      rule is activated --&gt;<br />    &lt;java:consequence&gt;<br />        stockOffer.setRecommendPurchase(<br />                              StockOffer.YES);  <br />          printStock(stockOffer);<br />    &lt;/java:consequence&gt;<br />  &lt;/rule&gt;<br />&lt;/rule-set&gt;</pre><br /><br />这个规则文件有几个有意思的部分：<br />·        在XML-Schema定义被引入Java对象后，我们也把它引入到我们的规则中。这些对象来自于所需的Java类库。<br />·        功能和标准的Java代码相结合。这样的话，我们就可以通过功能日志了解到底发生了什么。<br />·        规则设置可以包括一个或多个规则。<br />·        每条规则可以有参数（StockOffer类）。需要满足一个或多个条件，并且当条件满足时就执行相应的结果。<br /><br />修改，编译了代码后，再运行Junit测试模拟器。这次，如图3所示，商务规则被调用了，逻辑评价正确，测试通过。祝贺—你已经创建了你的第一个基于规则的应用！<br /><br /><img onmouseover="javascript:imgShowTip(this);" style="DISPLAY: inline" onclick="javascript:imgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/forum/2005_12_12_231602_YUwJXgaqhC.gif" onload="javascript:imgLoad(this);" border="0" twffan="done" /><br />图3。成功的Junit测试<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">灵活的规则</span></b><br /><br />刚建好系统，你示范了上面的原型给商务用户，这时他们想起先前忘了给你提到几个规则了。新规则之一是当数量是负值时，不能够交易股票。你说“没问题，”，然后回到你的座位，借可靠的知识，你能迅速的改进系统。<br />第一件要做的事情是更新你的模拟器，把下面的代码加到BusinessRuleTest.java:<br /><br /><b>清单5:</b><br /><br /><pre class="overflow">/**<br />*测试买股票确保系统不接受负值<br />*/<br />  public void testNegativeStockBuy() <br />                                throws Exception{<br />//用模拟值创建股票<br />      StockOffer testOffer = new StockOffer();<br />        testOffer.setStockName("MEGACORP");<br />        testOffer.setStockPrice(-22);<br />        testOffer.setStockQuantity(1000);<br />//运行规则<br />        BusinessLayer<br />              .evaluateStockPurchase(testOffer);<br />//是否达到我们的期望？<br />        assertTrue("NO".equals(<br />          testOffer.getRecommendPurchase()));<br />}</pre><br /><br />这是为商务用户描述的新规则的测试。如果测试这个Junit测试，如预期的新测试失败了。我们需要加这个新规则到.drl文件中，如下所示。<br /><br /><b>清单6:</b><br /><pre class="overflow">&lt;!-- Ensure that negative prices <br />                            are not accepted--&gt;      <br />  &lt;rule name="Stock Price Not Negative"&gt;<br />    &lt;!-- Parameters we can pass into <br />                          the business rule --&gt;<br />    &lt;parameter identifier="stockOffer"&gt;<br />      &lt;class&gt;StockOffer&lt;/class&gt;<br />    &lt;/parameter&gt;<br />    &lt;!-- Conditions or 'Left Hand Side' (LHS) <br />       that must be met for rule to fire --&gt;<br />    &lt;java:condition&gt;<br />      stockOffer.getStockPrice() &lt; 0<br />    &lt;/java:condition&gt;<br />    &lt;!-- What happens when the business rule <br />                              is activated --&gt;<br />    &lt;java:consequence&gt;<br />      stockOffer.setRecommendPurchase(<br />                                  StockOffer.NO);       <br />      printStock(stockOffer);<br />    &lt;/java:consequence&gt;<br />  &lt;/rule&gt;</pre><br /><br />这个规则的和前一个类似，期望&lt;java:condition&gt;不同（测试负值）和&lt;java:consequence&gt;设置建议购买为No。再次运行测试/模拟器，这次测试通过。<br /><br />这样的话，如果你习惯使用过程编程（象大多数Java 编程者），或许你会发愁挠头：一个文件包含两个独立的商务规则，而且我们也没有告诉规则引擎这两个规则哪个更重要。然而，股票价格（-22）也符合两个规则（它小于0也小于100）。不论如何，我们得到了正确的结果，即使交换规则的顺序。这是怎么工作的那？<br /><br />下面控制台输出的摘录帮助我们明白到底发生了什么。我们看到两个规则都被触发了（[activationfired]行）并且Recommend Buy先被置为Yes然后被置为No。Drools是如何以正确的顺序来触发这些规则的那？如果你看Stock Price Low Enough规则，就会看到其中的一个条件recommendPurchase()是null.这就足以让Drools决定Stock Price Low Enough规则应该先于Stock Price Not Negative规则触发。这个过程就是冲突解决方案。<br /><br /><b>清单7:</b><br /><pre class="overflow">FIRE RULES<br />----------<br />[ConditionTested: rule=Stock Price Not Negative; <br />  condition=[Condition: stockOffer.getStockPrice() <br />  &lt; 0]; passed=true; tuple={[]}]<br />[ActivationCreated: rule=Stock Price Not Negative; <br />  tuple={[]}]<br />[ObjectAsserted: handle=[fid:2];<br />   object=net.firstpartners.rp.StockOffer@16546ef]<br />[ActivationFired: rule=Stock Price Low Enough; <br />   tuple={[]}]<br />[ActivationFired: rule=Stock Price Not Negative; <br />   tuple={[]}]<br />Name:MEGACORP Price: -22 BUY:YES<br />Name:MEGACORP Price: -22 BUY:NO</pre><br /><br />如果你是个过程编程者，无论你认为这是多聪明，你仍然不能完全的信任它。这是为什么我们使用单元测试/模拟器：“辛苦的”Junit测试（使用通用Java代码）保证规则引擎用我们关注的行来做决定。（不要花费上亿在一些无价值的股票上！）同时，规则引擎的强大和灵活性让我们能够迅速开发商务逻辑。<br />稍后，我们将看到更多冲突解决方案的经典的方式。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">冲突解决方案</span></b><br /><br />在商务这边，人们真的印象深刻并别开始通过可能的选择来思考。他们看到XYZ公司股票的问题并且决定执行一条新规则:如果XYZ公司的股价低于10欧元，就仅仅买XYZ公司的股票。<br />象上次，加测试到模拟器中，在规则文件中加入新的商务规则，如下所列。首先，在BusinessRuleTest.java中添加新方法。<br /><br /><b>清单8:</b><br /><pre class="overflow">/**<br />*确保系统系统在XYZ公司股价便宜时就购买他们的股票<br />*/<br />public void testXYZStockBuy() throws Exception{<br />//用模拟值创建股票<br />  StockOffer testOfferLow = new StockOffer();<br />  StockOffer testOfferHigh = new StockOffer();<br />                <br />  testOfferLow.setStockName("XYZ");<br />  testOfferLow.setStockPrice(9);<br />  testOfferLow.setStockQuantity(1000);<br />                <br />  testOfferHigh.setStockName("XYZ");<br />  testOfferHigh.setStockPrice(11);<br />  testOfferHigh.setStockQuantity(1000);<br />//运行规则<br />  BusinessLayer.evaluateStockPurchase(<br />    testOfferLow);<br />  assertTrue("YES".equals(<br />    testOfferLow.getRecommendPurchase()));<br />                <br />  BusinessLayer.evaluateStockPurchase(<br />    testOfferHigh);<br />  assertTrue("NO".equals(<br />    testOfferHigh.getRecommendPurchase()));             <br />}</pre><br /><br />然后，在BusinessRules.drl中加个新&lt;规则&gt;:<br /><br /><b>清单10:</b><br />  <pre class="overflow">&lt;rule name="XYZCorp" salience="-1"&gt;<br />   &lt;!-- Parameters we pass to rule --&gt;<br />   &lt;parameter identifier="stockOffer"&gt;<br />     &lt;class&gt;StockOffer&lt;/class&gt;<br />   &lt;/parameter&gt;<br />    <br />   &lt;java:condition&gt;<br />     stockOffer.getStockName().equals("XYZ")<br />   &lt;/java:condition&gt; <br />   &lt;java:condition&gt;<br />     stockOffer.getRecommendPurchase() == null<br />   &lt;/java:condition&gt;<br />   &lt;java:condition&gt;<br />     stockOffer.getStockPrice() &gt; 10<br />   &lt;/java:condition&gt;<br />        <br />   &lt;!-- What happens when the business <br />                                rule is activated --&gt;<br />   &lt;java:consequence&gt; <br />     stockOffer.setRecommendPurchase(<br />       StockOffer.NO);  <br />     printStock(stockOffer);<br />   &lt;/java:consequence&gt;<br />  &lt;/rule&gt;</pre><br /><br />注意到商务规则文件中，规则名字后，我们设置salience为-1（比如，到现在我们说明的所有规则中的最低优先级）。系统冲突（意味着Drools在触发那个规则的顺序上作决定）的大多数规则给出了将达到的规则的条件。缺省的决定方法如下：.<br />·        显著性:如上列出的我们分配的值。 <br />·        崭新性：我们使用规则的次数。 <br />·        复杂性：第一次触发的更复杂的特定规则。 <br />·        装载顺序：那个规则被装载的顺序。<br />如果我们不说明这个例子中规则的显著性，将会发生的是： <br />·        XYZ公司规则（“如果股票价格超过10欧元买XYZ”）将被首先触发（推荐买标记的状态被置为No）。 <br />·        然后是更多的普通规则被触发（“买所有低于100的股票”），推荐买标记的状态被置为yes。<br /><br />这将得到我们不期望的结果。然而，我们的例子设置了显著性因素，用例及商务规则就会如我们期望的运行了。<br /><br />大多数情况下，书写清楚的规则且设置显著性将为Drools提供足够的信息来选择触发规则的顺序。有时，我们想整个的改变解决规则冲突的方式。以下是一个如何改变的例子，其中我告诉规则引擎首先触发最简单的规则。要注意的是，改变冲突解决方案是要小心，因为它能根本的改变规则引擎的规则—用清楚的写得恰当的规则能预先解决许多问题。<br /><br /><b>清单11:</b><br /><pre class="overflow">//生成冲突解决者的列表<br />  ConflictResolver[] conflictResolvers = <br />    new ConflictResolver[] {<br />      SalienceConflictResolver.getInstance(),<br />      RecencyConflictResolver.getInstance(),<br />        SimplicityConflictResolver.getInstance(),<br />        LoadOrderConflictResolver.getInstance()<br />    };<br />//包装成合成解决者<br />  CompositeConflictResolver resolver = <br />    new CompositeConflictResolver(<br />      conflictResolvers); <br />//当装载规则时，说明这个解决者<br />  businessRules = RuleBaseLoader.loadFromUrl(<br />    BusinessLayer.class.getResource( <br />      BUSINESS_RULE_FILE),resolver);</pre><br /><br />对于我们的简单的应用，由Junit测试驱动，我们不需要改变Drools解决规则冲突的方式。了解冲突解决方案是如何工作的对我们是非常有帮助的，尤其是当应用需要满足更复杂根严格的需求试。<br /><br /><b><span style="FONT-SIZE: 16px" twffan="done">结论</span></b><br /><br />这篇文章论证了许多编程者遇到过的问题：如何定制复杂的商务逻辑。我们示范了一个用Drools为解决方案的简单应用并介绍了基于规则编程的概念，包括在运行时这些规则是如何被处理的。稍后，接下来的文章将以这些为基础来展示在企业级Java应用中是如何使用它的。<br /><br /><br /><span style="FONT-SIZE: 16px" twffan="done"><b>资源</b></span><br />·下载例子所有源代码:<a href="http://sourceforge.net/project/showfiles.php?group_id=99476&amp;package_id=158438" target="_new">源代码</a><br />·Matrix-Java开发者社区:<a href="http://www.matrix.org.cn/" target="_new">http://www.matrix.org.cn</a><br />·onjava.com:<a href="http://onjava.com/" target="_new">onjava.com</a><br />·<a href="http://www.drools.org/" target="_new">Drools项目主页</a><br />·<a href="http://www.jroller.com/page/eu/20040810" target="_new">Drools规则信息</a><br />·<a href="http://www.theserverside.com/articles/article.tss?l=Drools" target="_new">“Drools和规则引擎介绍”由Drools项目领导 </a><br />·<a href="http://www.geocities.com/CapitolHill/5910/drltk/instructions.htm" target="_new">Drools规则计划文件</a><br />·<a href="http://javaboutique.internet.com/tutorials/rules_engine/" target="_new">JSR-94, Java规则引擎，概略 </a><br />·<a href="http://herzberg.ca.sandia.gov/jess/index.shtml" target="_new">Jess Jave规则引擎</a><br />·<a href="http://jena.sourceforge.net/" target="_new">Jena语义和规则引擎</a><br />·<a href="http://jcp.org/aboutJava/communityprocess/review/jsr094/" target="_new">JSR-94主页</a><br />·<a href="http://www.manning.com/friedman-hill" target="_new">Jess在Action主页</a><br />·<a href="http://herzberg.ca.sandia.gov/jess/zen.shtml" target="_new">“商务规则思想”（基于Jess）</a><br />·<a href="http://www.aaai.org/AITopics/html/expert.html" target="_new">“规则系统的一般介绍” </a><br />·<a href="http://herzberg.ca.sandia.gov/jess/docs/61/rete.html" target="_new">“Rete算法的Jess执行”</a><br /><br />保尔 布朗已经通过FirstPartners.net网站为企业级Java咨询了约7年的时间。<br /><img src ="http://www.blogjava.net/sharkafeng/aggbug/59453.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sharkafeng/" target="_blank">The Spark of Thinking</a> 2006-07-21 16:58 <a href="http://www.blogjava.net/sharkafeng/articles/59453.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java规则引擎与其API应用详解(转)</title><link>http://www.blogjava.net/sharkafeng/articles/59449.html</link><dc:creator>The Spark of Thinking</dc:creator><author>The Spark of Thinking</author><pubDate>Fri, 21 Jul 2006 08:57:00 GMT</pubDate><guid>http://www.blogjava.net/sharkafeng/articles/59449.html</guid><wfw:comment>http://www.blogjava.net/sharkafeng/comments/59449.html</wfw:comment><comments>http://www.blogjava.net/sharkafeng/articles/59449.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sharkafeng/comments/commentRss/59449.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sharkafeng/services/trackbacks/59449.html</trackback:ping><description><![CDATA[　　<span class="main" twffan="done">本文对Java规则引擎与其API(JSR-94)及相关实现做了较详细的介绍，对其体系结构和API应用有较详尽的描述，并指出Java规则引擎,规则语言，JSR-94的相互关系,以及JSR-94的不足之处和展望。 </span><p class="main">　　复杂企业级项目的开发以及其中随外部条件不断变化的业务规则(business logic),迫切需要分离商业决策者的商业决策逻辑和应用开发者的技术决策，并把这些商业决策放在中心数据库或其他统一的地方，让它们能在运行时（即商务时间）可以动态地管理和修改从而提供软件系统的柔性和适应性。规则引擎正是应用于上述动态环境中的一种解决方法。</p><p class="main">　　本文第一部分简要介绍了规则引擎的产生背景和基于规则的专家系统，第二部分介绍了什么是规则引擎及其架构和算法，第三部分介绍了商业产品和开源项目实现等各种Java规则引擎，第四部分对Java规则引擎API（JSR-94）作了详细介绍，讲解了其体系结构，管理API和运行时API及相关安全问题，第五部分则对规则语言及其标准化作了探讨，第六部分给出了一个使用Java规则引擎API的简单示例，第七部分给予小结和展望。</p><p class="main">　　<strong>1、 介绍</strong></p><p class="main">　　<font color="#0000ff"><strong>1.1 规则引擎产生背景</strong></font></p><p class="main">　　企业管理者对企业级IT系统的开发有着如下的要求：(1)为提高效率，管理流程必须自动化，即使现代商业规则异常复杂(2)市场要求业务规则经常变化，IT系统必须依据业务规则的变化快速、低成本的更新(3)为了快速、低成本的更新，业务人员应能直接管理IT系统中的规则，不需要程序开发人员参与。</p><p class="main">　　而项目开发人员则碰到了以下问题:(1)程序=算法+数据结构，有些复杂的商业规则很难推导出算法和抽象出数据模型(2)软件工程要求从需求-&gt;设计-&gt;编码，然而业务规则常常在需求阶段可能还没有明确，在设计和编码后还在变化，业务规则往往嵌在系统各处代码中(3)对程序员来说，系统已经维护、更新困难，更不可能让业务人员来管理。</p><p class="main">　　基于规则的专家系统的出现给开发人员以解决问题的契机。规则引擎由基于规则的专家系统中的推理引擎发展而来。下面简要介绍一下基于规则的专家系统。</p><p class="main">　　<font color="#0000ff"><strong>1.2 基于规则的专家系统(RBES)</strong></font></p><p class="main">　　专家系统是人工智能的一个分支，它模仿人类的推理方式，使用试探性的方法进行推理，并使用人类能理解的术语解释和证明它的推理结论。专家系统有很多分类：神经网络、基于案例推理和基于规则系统等。</p><p class="main">　　RBES包括三部分：Rule Base（knowledge base）、Working Memory（fact base）和Inference Engine（推理引擎）。它们的结构如下所示：</p><p class="main">　　图1.基于规则的专家系统组成</p><p align="center"><img height="171" src="http://tech.csai.cn/sa/images/no000138_1.jpg" width="440" twffan="done" /></p><p class="main"><br />　　如上图所示，推理引擎包括三部分：Pattern Matcher、Agenda和Execution Engine。Pattern Matcher何时执行哪个规则；Agenda管理PatternMatcher挑选出来的规则的执行次序；Execution Engine负责执行规则和其他动作。</p><p class="main">　　推理引擎通过决定哪些规则满足事实或目标，并授予规则优先级，满足事实或目标的规则被加入议程。存在两者推理方式：演绎法（Forward-Chaining正向链）和归纳法（Backward-Chaining反向链）。演绎法从一个初始的事实出发，不断地应用规则得出结论（或执行指定的动作）。而归纳法则是从假设出发，不断地寻找符合假设的事实。</p><p class="main">　　<strong>2、 规则引擎</strong></p><p class="main">　<font color="#0000ff"><strong>　2.1 业务规则</strong></font><br />　<br />　　一个业务规则包含一组条件和在此条件下执行的操作，它们表示业务规则应用程序的一段业务逻辑。业务规则通常应该由业务分析人员和策略管理者开发和修改，但有些复杂的业务规则也可以由技术人员使用面向对象的技术语言或脚本来定制。业务规则的理论基础是:设置一个或多个条件，当满足这些条件时会触发一个或多个操作。</p><p class="main">　　<font color="#0000ff"><strong>2.2 规则引擎</strong></font></p><p class="main">　　什么是规则引擎？规则引擎是如何执行规则的？这可以称之为"什么"与"如何"的问题。到底规则引擎是什么还是目前业界一个比较有争议的问题，在JSR-94种也几乎没有定义。可以这样认为充分定义和解决了"如何"的问题，"什么"问题本质上也迎刃而解。也许这又是一种"先有蛋还是先有鸡"哲学争论。今后标准规则语言的定义和推出及相关标准的制定应该可以给这样的问题和争论划上一个句号。本文中，暂且这样述说什么是规则引擎：规则引擎由推理引擎发展而来，是一种嵌入在应用程序中的组件，实现了将业务决策从应用程序代码中分离出来，并使用预定义的语义模块编写业务决策。接受数据输入，解释业务规则，并根据规则做出业务决策。</p><p class="main">　　<font color="#0000ff"><strong>2.3 规则引擎的使用方式</strong></font></p><p class="main">　　由于规则引擎是软件组件，所以只有开发人员才能够通过程序接口的方式来使用和控制它，规则引擎的程序接口至少包含以下几种API：加载和卸载规则集的API；数据操作的API；引擎执行的API。开发人员在程序中使用规则引擎基本遵循以下5个典型的步骤：创建规则引擎对象；向引擎中加载规则集或更换规则集；向引擎提交需要被规则集处理的数据对象集合；命令引擎执行;导出引擎执行结果，从引擎中撤出处理过的数据。使用了规则引擎之后，许多涉及业务逻辑的程序代码基本被这五个典型步骤所取代。 </p><p class="main">　　一个开放的业务规则引擎应该可以"嵌入"在应用程序的任何位置，不同位置的规则引擎可以使用不同的规则集，用于处理不同的数据对象。此外，对使用引擎的数量没有限制。</p><p class="main">　　<font color="#0000ff"><strong>2.4 规则引擎架构与推理</strong></font></p><p class="main">　　规则引擎的架构如下图所示：</p><p class="main">　　图2. 业务规则引擎架构</p><p align="center"><img height="329" src="http://tech.csai.cn/sa/images/no000138_2.jpg" width="492" twffan="done" /></p><p><br />　　<span class="main" twffan="done">规则引擎的推理步骤如下：a. 将初始数据（fact）输入至工作内存(Working Memory)。b. 使用Pattern Matcher将规则库(Rules repository)中的规则（rule）和数据（fact）比较。c. 如果执行规则存在冲突（conflict），即同时激活了多个规则，将冲突的规则放入冲突集合。d. 解决冲突，将激活的规则按顺序放入Agenda。e. 执行Agenda中的规则。重复步骤b至e，直到执行完毕Agenda中的所有规则。</span></p><p class="main">　　任何一个规则引擎都需要很好地解决规则的推理机制和规则条件匹配的效率问题。</p><p class="main">　　当引擎执行时，会根据规则执行队列中的优先顺序逐条执行规则执行实例，由于规则的执行部分可能会改变工作区的数据对象，从而会使队列中的某些规则执行实例因为条件改变而失效，必须从队列中撤销，也可能会激活原来不满足条件的规则，生成新的规则执行实例进入队列。于是就产生了一种"动态"的规则执行链，形成规则的推理机制。这种规则的"链式"反应完全是由工作区中的数据驱动的。 </p><p class="main">　　规则条件匹配的效率决定了引擎的性能，引擎需要迅速测试工作区中的数据对象，从加载的规则集中发现符合条件的规则，生成规则执行实例。1982年美国卡耐基·梅隆大学的Charles L. Forgy发明了一种叫Rete算法，很好地解决了这方面的问题。目前世界顶尖的商用业务规则引擎产品基本上都使用Rete算法。</p><p class="main">　　<font color="#0000ff"><strong>2.5 规则引擎的算法</strong></font><br />　<br />　　大部分规则引擎产品的算法，基本上都来自于Dr. Charles Forgy在1979年提出的RETE算法及其变体，Rete算法是目前效率最高的一个Forward-Chaining推理算法，Drools项目是Rete算法的一个面向对象的Java实现，Rete算法其核心思想是将分离的匹配项根据内容动态构造匹配树，以达到显著降低计算量的效果。</p><p class="main">　　<strong>3、 Java规则引擎</strong><br />　<br />　　目前主流的规则引擎组件多是基于Java和C++程序语言环境，已经有多种Java规则引擎商业产品与开源项目的实现，其中有的已经支持JSR94，有的正朝这个方向做出努力，列出如下：</p><p class="main">　　<font color="#0000ff"><strong>3.1 Java规则引擎商业产品</strong></font></p><p class="main">　　Java规则引擎商业产品主要有（Jess不是开源项目，它可以免费用于学术研究，但用于商业用途则要收费）：</p><p align="center"><img height="291" src="http://tech.csai.cn/sa/images/no000138-3.gif" width="550" twffan="done" /></p><p>　<font color="#0000ff"><strong>　<span class="main" twffan="done">3.2 Java规则引擎开源项目</span></strong></font></p><p class="main">　　开源项目的实现主要包括：</p><p class="main">　　Drools - Drools规则引擎应用Rete算法的改进形式Rete-II算法。从内部机制上讲，它使用了和Forgy的算法相同的概念和方法，但是增加了可与面向对象语言无缝连接的节点类型。</p><p class="main">　　Mandarax 基于反向推理（归纳法）。能够较容易地实现多个数据源的集成。例如，数据库记录能方便地集成为事实集(facts sets)，reflection用来集成对象模型中的功能。目前不支持JSR 94</p><p class="main">　　OFBiz Rule Engine - 支持归纳法(Backward chaining).最初代码基于Steven John Metsker的"Building Parsers in Java"，不支持JSR 94</p><p class="main">　　JLisa - JLisa是用来构建业务规则的强大框架，它有着扩展了LISP优秀特色的优点,比Clips还要强大.这些特色对于多范例软件的开发是至关重要的.支持JSR 94</p><p class="main">　　其它的开源项目实现有诸如Algernon, TyRuBa, JTP, JEOPS, InfoSapient, RDFExpert, Jena 2, Euler, JLog, Pellet OWL Reasoner, Prova, OpenRules, SweetRules, JShop2等等。</p><p class="main">　　<strong>4、 Java规则引擎API(JSR-94)</strong></p><p class="main">　　<font color="#0000ff"><strong>4.1 简介</strong></font></p><p class="main">　　过去大部分的规则引擎开发并没有规范化，有其自有的API，这使得其与外部程序交互集成不够灵活。转而使用另外一种产品时往往意味需要重写应用程序逻辑和API调用，代价较大。规则引擎工业中标准的缺乏成为令人关注的重要方面。2003年11月定稿并于2004年8月最终发布的JSR 94（Java规则引擎API）使得Java规则引擎的实现得以标准化。</p><p class="main">　　Java规则引擎API由javax.rules包定义，是访问规则引擎的标准企业级API。Java规则引擎API允许客户程序使用统一的方式和不同厂商的规则引擎产品交互，就像使用JDBC编写独立于厂商访问不同的数据库产品一样。Java规则引擎API包括创建和管理规则集合的机制，在Working Memory中添加，删除和修改对象的机制，以及初始化，重置和执行规则引擎的机制。</p><p class="main">　　<font color="#0000ff"><strong>4.2 简介Java规则引擎API体系结构</strong></font></p><p class="main">　　Java规则引擎API分为两个主要部分:运行时客户API(the Runtime client API)和规则管理API(the rules administration API)。</p><p class="main">　<font color="#ff0000"><strong>　4.2.1规则管理API</strong></font></p><p class="main">　　规则管理API在javax.rules.admin中定义,包括装载规则以及与规则对应的动作(执行集 execution sets)以及实例化规则引擎。规则可以从外部资源中装载,比如说URI,Input streams, XML streams和readers等等.同时管理API提供了注册和取消注册执行集以及对执行集进行维护的机制。使用admin包定义规则有助于对客户访问运行规则进行控制管理,它通过在执行集上定义许可权使得未经授权的用户无法访问受控规则。</p><p class="main">　　管理API使用类RuleServiceProvider来获得规则管理(RuleAdministrator)接口的实例.规则管理接口提供方法注册和取消注册执行集.规则管理器(RuleAdministrator)提供了本地和远程的RuleExecutionSetProvider.在前面已提及,RuleExecutionSetProvider负责创建规则执行集.规则执行集可以从如XML streams, input streams等来源中创建.这些数据来源及其内容经汇集和序列化后传送到远程的运行规则引擎的服务器上.大多数应用程序中,远程规则引擎或远程规则数据来源的情况并不多见.为了避免这些情况中的网络开销,API规定了可以从运行在同一JVM中规则库中读取数据的本地RuleExecutionSetProvider.</p><p class="main">　　规则执行集接口除了拥有能够获得有关规则执行集的方法,还有能够检索在规则执行集中定义的所有规则对象.这使得客户能够知道规则集中的规则对象并且按照自己需要来使用它们。 </p><p class="main">　　<font color="#ff0000"><strong>4.2.2 运行时API</strong></font></p><p class="main">　　运行时API定义在javax.rules包中,为规则引擎用户运行规则获得结果提供了类和方法。运行时客户只能访问那些使用规则管理API注册过的规则，运行时API帮助用户获得规则对话并且在这个对话中执行规则。</p><p class="main">　　运行时API提供了对厂商规则引擎API实现的类似于JDBC的访问方法.规则引擎厂商通过类RuleServiceProvider(类RuleServiceProvider提供了对具体规则引擎实现的运行时和管理API的访问)将其规则引擎实现提供给客户,并获得RuleServiceProvider唯一标识规则引擎的URL.</p><p class="main">　　URL推荐标准用法是使用类似"com.mycompany.myrulesengine.rules.RuleServiceProvider"这样的Internet域名空间,这将有助于访问URL的唯一性.类RuleServiceProvider内部实现了规则管理和运行时访问所需的接口.所有的RuleServiceProvider要想被客户所访问都必须用RuleServiceProviderManager进行注册。注册方式类似于JDBC API的DriverManager和Driver。</p><p class="main">　　运行时接口是运行时API的关键部分.运行时接口提供了用于创建规则会话(RuleSession)的方法,规则会话如前所述是用来运行规则的.运行时API同时也提供了访问在service provider注册过的所有规则执行集(RuleExecutionSets).规则会话接口定义了客户使用的会话的类型,客户根据自己运行规则的方式可以选择使用有状态会话或者无状态会话。</p><p class="main">　　无状态会话的工作方式就像一个无状态会话bean.客户可以发送单个输入对象或一列对象来获得输出对象.当客户需要一个与规则引擎间的专用会话时,有状态会话就很有用.输入的对象通过addObject() 方法可以加入到会话当中.同一个会话当中可以加入多个对象.对话中已有对象可以通过使用updateObject()方法得到更新.只要客户与规则引擎间的会话依然存在,会话中的对象就不会丢失。</p><p class="main">　　RuleExecutionSetMetaData接口提供给客户让其查找规则执行集的元数据(metadata).元数据通过规则会话接口(RuleSession Interface)提供给用户。</p><p class="main">　　使用运行时Runtime API的代码片断如下所示:</p><table height="25" width="100%" align="center" border="1"><tbody><tr><td bgcolor="#cccccc">RuleServiceProvider ruleProvider = RuleServiceProviderManager.getRuleServiceProvider　　　<br />　　("com.mycompany.myrulesengine.rules. RuleServiceProvider"); <br />RuleRuntime ruleRuntime = ruleProvider.getRuleRuntime(); <br />StatelessRuleSession ruleSession = (StatelessRuleSession)ruleRuntime.createRuleSession(ruleURL, 　　　null, RuleRuntime.STTELESS_SESSION_TYPE); <br />List inputRules = new ArrayList(); <br />inputRules.add(new String("Rule 1")); <br />inputRules.add(new Integer(1)); <br />List resultRules = ruleSession.executeRules(inputRules);</td></tr></tbody></table><p class="main">　　<strong><font color="#0000ff">4.3 Java规则引擎API安全问题</font></strong><br />　　<br />　　规则引擎API将管理API和运行时API加以分开,从而为这些包提供了较好粒度的安全控制.规则引擎API并没有提供明显的安全机制,它可以和J2EE规范中定义的标准安全API联合使用.安全可以由以下机制提供,如Java authentication and authorization service (JAAS),the Java cryptography extension (JCE),Java secure Socket Extension (JSSE),或者其它定制的安全API.JAAS能被用来定义规则执行集的许可权限,从而只有授权用户才能访问。</p><p class="main">　　<font color="#0000ff"><strong>4.4 异常与日志</strong></font></p><p class="main">　　规则引擎API定义了javax.rules.RuleException作为规则引擎异常层次的根类.所有其它异常都继承于这个根类.规则引擎中定义的异常都是受控制的异常(checked exceptions),所以捕获异常的任务就交给了规则引擎。规则引擎API没有提供明确的日志机制,但是它建议将Java Logging API用于规则引擎API。</p><p class="main">　<font color="#0000ff"><strong>　4.5 JSR 94 小结</strong></font></p><p class="main">　　JSR 94 为规则引擎提供了公用标准API,仅仅为实现规则管理API和运行时API提供了指导规范,并没有提供规则和动作该如何定义以及该用什么语言定义规则,也没有为规则引擎如何读和评价规则提供技术性指导.JSR 94规范将上述问题留给了规则引擎的厂商.在下一节我将简要介绍一下规则语言。</p><p class="main">　　<strong>5、 规则语言</strong></p><p class="main">　　JSR 94中没有涉及用来创建规则和动作的语言.规则语言是规则引擎应用程序的重要组成部分,所有的业务规则都必须用某种语言定义并且存储于规则执行集中,从而规则引擎可以装载和处理他们。</p><p class="main">　　由于没有关于规则如何定义的公用规范,市场上大多数流行的规则引擎都有其自己的规则语言，目前便有许多种规则语言正在应用，因此，当需要将应用移植到其他的Java规则引擎实现时，可能需要变换规则定义，如将Drools私有的DRL规则语言转换成标准的ruleML，Jess规则语言转换成ruleML等。这个工作一般由XSLT转换器来完成。</p><p class="main">　　多种规则语言的使用使得不同规则引擎实现之间的兼容性成为问题.通用的规则引擎API或许可以减轻不同厂家API之间的问题,但公用规则语言的缺乏将仍然阻碍不同规则引擎实现之间的互操作性.尽管业界在提出公用规则语言上做出了一些努力, 比如说RuleML,SRML的出现,但距离获得绝大部分规则引擎厂商同意的公用标准还有很长的路要走。</p><p class="main">　<strong>　6、 Java规则引擎API使用示例 </strong></p><p class="main">　　<font color="#0000ff"><strong>6.1 设置规则引擎</strong></font></p><p class="main">　　Java规则引擎的管理活动阶段开始于查找一个合适的javax.rules.RuleServiceProvider对象，这个对象是应用程序访问规则引擎的入口。在J2EE环境中，你可能可以通过JNDI获得RuleServiceProvider。否则，你可以使用javax.rules.RuleServiceProviderManager类：</p><table width="100%" align="center" border="1"><tbody><tr><td class="main" bgcolor="#cccccc">javax.rules.RuleServiceProviderManager class:<br />String implName = "org.jcp.jsr94.ri.RuleServiceProvider";<br />Class.forName(implName);<br />RuleServiceProvider serviceProvider = RuleServiceProviderManager.getRuleServiceProvider</td></tr></tbody></table><p class="main">　　拥有了RuleServiceProvider对象，你就可以获得一个javax.rules.admin.RuleAdministrator类。从RuleAdministrator类中，你可以得到一个RuleExecutionSetProvider，从类名可以知道，它用于创建javax.rules.RuleExecutionSets对象。RuleExecutionSet基本上是一个装入内存的，准备好执行的规则集合。</p><p class="main">　　包javax.rules.admin包括两个不同的RuleExecutionSetProvider类。RuleExecutionSetProvider类本身包括了从Serializable对象创建RuleExecutionSets的方法，因此在规则引擎位于远程服务器的情况下，仍然可以使用RuleExecutionSetProvider类，构造器的参数可以通过RMI来传递。另一个类是LocalRuleExecutionSetProvider，包含了其他方法，用于从非Serializable资源（如java.io.Reader－本地文件）创建RuleExectionSets。假设拥有了一个RuleServiceProvider对象，你可以从本地文件rules.xml文件创建一个RuleExectionSet对象。如以下的代码所示：</p><table height="25" width="98%" align="center" border="1"><tbody><tr><td class="main" bgcolor="#cccccc">RuleAdministrator admin = serviceProvider.getRuleAdministrator(); <br />HashMap properties = new HashMap(); <br />properties.put("name", "My Rules"); <br />properties.put("description", "A trivial rulebase"); <br />FileReader reader = new FileReader("rules.xml"); <br />RuleExecutionSet ruleSet = null; <br />　try { <br />　　　 LocalRuleExecutionSetProvider lresp =admin.getLocalRuleExecutionSetProvider(properties); <br />ruleSet = lresp.createRuleExecutionSet(reader, properties); <br />　} finally { <br />　 reader.close(); <br />　} </td></tr></tbody></table><p class="main">　　接下来，你可以使用RuleAdministrator注册获得的RuleExecutionSet，并给它分配一个名称。在运行时，你可以用同一个名称创建一个RuleSession；该RuleSession使用了这个命名的RuleExecutionSet。参见下面的用法：admin.registerRuleExecutionSet("rules", ruleSet, properties);</p><p class="main">　　<font color="#0000ff"><strong>6.2 执行规则引擎</strong></font></p><p class="main">　　在运行时阶段，你可以参见一个RuleSession对象。RuleSession对象基本上是一个装载了特定规则集合的规则引擎实例。你从RuleServiceProvider得到一个RuleRuntime对象，接下来，从javax.rules.RuleRuntime得到RuleSession对象。</p><p class="main">　　RuleSession分为两类：stateful和stateless。它们具有不同的功能。StatefulRuleSession的Working Memory能够在多个方法调用期间保存状态。你可以在多个方法调用期间在Working Memory中加入多个对象，然后执行引擎，接下来还可以加入更多的对象并再次执行引擎。相反，StatelessRuleSession类是不保存状态的，为了执行它的executeRules方法，你必须为Working Memory提供所有的初始数据，执行规则引擎，得到一个内容列表作为返回值。</p><p class="main">　　下面的例子中，我们创建一个StatefulRuleSession实例，添加两个对象（一个Integer和一个String）到Working Memory，执行规则，然后得到Working Memory中所有的内容，作为java.util.List对象返回。最后，我们调用release方法清理RuleSession：</p><table width="99%" align="center" border="1"><tbody><tr><td class="main" bgcolor="#cccccc">RuleRuntime runtime = rsp.getRuleRuntime(); <br />StatefulRuleSession session=(StatefulRuleSession)runtime.createRuleSession("rules", 　　　 　　　　　 properties,RuleRuntime.STATEFUL_SESSION_TYPE);　<br />session.addObject(new Integer(1)); <br />session.addObject("A string"); <br />session.executeRules(); <br />List results = session.getObjects(); <br />session.release();</td></tr></tbody></table><p class="main">　　<strong>7、 结束语</strong></p><p class="main">　　Java规则引擎API(JSR-94)允许客户程序使用统一的方式和不同厂商的规则引擎产品交互，一定程度上给规则引擎厂商提供了标准化规范。但其几乎没有定义什么是规则引擎，当然也没有深入到规则是如何构建和操纵的，规则调用的效用，规则与Java语言的绑定等方面。并且JSR-94在对J2EE的支持上也不足。规则语言的标准化，JSR-94的进一步的充实深化都有待研究</p><img src ="http://www.blogjava.net/sharkafeng/aggbug/59449.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sharkafeng/" target="_blank">The Spark of Thinking</a> 2006-07-21 16:57 <a href="http://www.blogjava.net/sharkafeng/articles/59449.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从“3-4年的.Net开发经验”想到的(转)</title><link>http://www.blogjava.net/sharkafeng/articles/59276.html</link><dc:creator>The Spark of Thinking</dc:creator><author>The Spark of Thinking</author><pubDate>Thu, 20 Jul 2006 10:20:00 GMT</pubDate><guid>http://www.blogjava.net/sharkafeng/articles/59276.html</guid><wfw:comment>http://www.blogjava.net/sharkafeng/comments/59276.html</wfw:comment><comments>http://www.blogjava.net/sharkafeng/articles/59276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sharkafeng/comments/commentRss/59276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sharkafeng/services/trackbacks/59276.html</trackback:ping><description><![CDATA[
		<p>我msn上有个朋友是做hr的，经常在他名字后面写一些招聘信息什么的。今天上来也不例外，说是要找“3－4年”工作经验的.Net开发人员。</p>
		<p>当然我不知道他们公司是怎么想的，不过我想在中国想找真正3-4年工作经验的.Net开发人员恐怕基本上找不到，就是找到几个恐怕也有一大半是吹的。因为.Net从成型到现在估计也就3到4年时间（可能还不到）。更不要说大规模开始应用了。</p>
		<p>以前还看过一个招聘高级J2EE工程师的广告，当然了，“高级”就是不一样，要求至少有5－6年J2EE开发经验。而大家当然都知道，6年前的1999年，J2EE才刚刚诞生。</p>
		<p>我记得毕业时候看那些公司的招聘广告，都是牛得不得了，恨不得把所有的条件都列上。英语要n级，要懂这个懂那个，什么c++,c,rup,oracle,sql server,linux,unix之类，反正是能想到的东西都要懂，地球上存在地东西都要会。我当时看着那么多的招聘广告，觉得自己没有几个能够得上人家的标准的。问问身边认识的人，好像也没有几个能够得上这样的标准。</p>
		<p>其实我们当然知道，这些都只是夸张而已。招聘的在招聘广告上掺水，应聘的在简历上掺水。等到大家真的互相了解了，对视嘿嘿一笑，什么n多的神技就如浮云般飘散。</p>
		<p>只是我有时候真不知道，这样是好还是坏。</p>
<img src ="http://www.blogjava.net/sharkafeng/aggbug/59276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sharkafeng/" target="_blank">The Spark of Thinking</a> 2006-07-20 18:20 <a href="http://www.blogjava.net/sharkafeng/articles/59276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>