??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲AV无码国产精品永久一区,亚洲福利在线观看,亚洲AV无码专区在线亚http://www.tkk7.com/junky/category/23629.htmlzh-cnThu, 28 Jun 2007 23:30:34 GMTThu, 28 Jun 2007 23:30:34 GMT60drools和spring的集?/title><link>http://www.tkk7.com/junky/archive/2007/06/28/126696.html</link><dc:creator>junky</dc:creator><author>junky</author><pubDate>Thu, 28 Jun 2007 00:57:00 GMT</pubDate><guid>http://www.tkk7.com/junky/archive/2007/06/28/126696.html</guid><wfw:comment>http://www.tkk7.com/junky/comments/126696.html</wfw:comment><comments>http://www.tkk7.com/junky/archive/2007/06/28/126696.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/junky/comments/commentRss/126696.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/junky/services/trackbacks/126696.html</trackback:ping><description><![CDATA[<div><strong>规则引擎?/strong><br>      Java规则引擎是推理引擎的一U,它v源于Z规则的专家系l?br>      Java规则引擎业务决{从应用E序代码中分d来,q用预定义的语义模块编写业务决{。Java规则引擎接受数据输入Q解释业务规则,q根据规则作Z务决{。从q个意义上来_它是软gҎ学在"x点分?上的一个重要的q展?br>      JSR-94规范定义了独立于厂商的标准APIQ开发h员可以通过q个标准的API使用Java规则引擎规范的不同品实现。但值得注意的是Q这个规范ƈ没有强制l一规则定义的语法,因此Q当需要将应用UL到其他的Java规则引擎实现Ӟ可能需要变换规则定义?/div> <div><br><strong>Z规则的专家系l(RBESQ?br></strong>       专家pȝ是h工智能的一个分支,它模仿hcȝ推理方式Q用试探性的Ҏq行推理Qƈ使用人类能理解的术语解释和证明它的推理结论。专家系l有很多分类Q神l网l、基于案例推理和Z规则pȝ{?br>       规则引擎则是Z规则的专家系l的一部分。ؓ了更深入的了解Java规则引擎Q下面简要地介绍Z规则的专家系l(RBESQ?/div> <div align=left><br>  <strong>RBES的技术架?br></strong>       RBES包括三部分:Rule BaseQknowledge baseQ、Working MemoryQfact baseQ和Rule EngineQ推理引擎)。它们的l构如下所C:</div> <div align=left> </div> <div align=center><img onmousewheel="return bbimg(this)" title=点击新窗口查看大?alt="" src="http://starrynight.blogdriver.com/diary/starrynight/inc/ruleengine.gif" width=200 onload="java_script_:if(this.width>200)this.width=200" border=0><br> </div> <div>       如上图所C,规则引擎包括三部分:Pattern Matcher、Agenda和Execution Engine。Pattern Matcher军_选择执行哪个规则Q何时执行规则;Agenda理PatternMatcher挑选出来的规则的执行次序;Execution Engine负责执行规则和其他动作?/div> <div><br>  <strong>RBES的推理(规则Q引?br></strong>       和hcȝ思维相对应,规则引擎存在两者推理方式:演绎法(Forward-ChainingQ和归纳法(Backward-ChainingQ。演l法从一个初始的事实出发Q不断地应用规则得出l论Q或执行指定的动作)。而归Ux则是从假讑և发,不断地寻扄合假讄事实?br>       Rete法是目前效率最高的一个Forward-Chaining推理法QDrools目是Rete法的一个面向对象的Java实现?br>       规则引擎的推理步骤如下:<br>       1. 初始数据(factQ输入Working Memory?br>       2. 使用Pattern Matcher比较规则QruleQ和数据QfactQ?br>       3. 如果执行规则存在冲突QconflictQ,卛_时激zM多个规则Q将冲突的规则放入冲H集合?br>       4. 解决冲突Q将Ȁzȝ规则按顺序放入Agenda?br>       5. 使用规则引擎执行Agenda中的规则。重复步??Q直到执行完毕所有Agenda中的规则?/div> <div><br><strong>JSR 94QJava规则引擎API</strong><br>       Z规则~程是一U声明式的编E技术,q种技术让你可以用试探性的规则而不是过E性的指o来解决问题。规则引擎是一个Y件模块,它决定了如何规则作用于推理数据。在保险业和金融服务业都q泛C用了Z规则的编E技术,当需要在大量的数据上应用复杂的规则时Q规则引擎技术特别有用?br>       Java规则引擎API由javax.rules包定义,是访问规则引擎的标准企业UAPI。Java规则引擎API允许客户E序使用l一的方式和不同厂商的规则引擎品交互,像使用JDBC~写独立于厂商访问不同的数据库品一栗Java规则引擎API包括创徏和管理规则集合的机制Q在Working Memory中添加,删除和修改对象的机制Q以及初始化Q重|和执行规则引擎的机制?/div> <div><br><strong>使用Java规则引擎API</strong><br>       Java规则引擎API把和规则引擎的交互分Zc:理zd和运行时zd。管理活动包括实例化规则引擎和装载规则。而运行时zd包括操作Working Memory和执行规则。如果你在J2SE环境中用Java规则引擎Q你可能需要在代码中执行以上所有的zd。相反,在J2EE环境中,Java规则引擎的管理活动是应用服务器的一部分。JSR 94的参考实现包括了一个JCAq接器,用于通过JNDI获得一个RuleServiceProvider?/div> <div><br>  <strong>讄规则引擎</strong><br>       Java规则引擎的管理活动阶D开始于查找一个合适的javax.rules.RuleServiceProvider对象Q这个对象是应用E序讉K规则引擎的入口。在J2EE环境中,你可能可以通过JNDI获得RuleServiceProvider。否则,你可以用javax.rules.RuleServiceProviderManagerc:<br>           javax.rules.RuleServiceProviderManager class: </div> <div>           String implName = "org.jcp.jsr94.ri.RuleServiceProvider";<br>           Class.forName(implName);<br>           RuleServiceProvider serviceProvider = RuleServiceProviderManager.getRuleServiceProvider(implName);<br>       一旦拥有了RuleServiceProvider对象Q你可以获得一个javax.rules.admin.RuleAdministratorcR从RuleAdministratorcMQ你可以得到一个RuleExecutionSetProviderQ从cd可以知道Q它用于创徏javax.rules.RuleExecutionSets对象。RuleExecutionSet基本上是一个装入内存的Q准备好执行的规则集合?br>       包javax.rules.admin包括两个不同的RuleExecutionSetProvidercRRuleExecutionSetProvidercLw包括了从Serializable对象创徏RuleExecutionSets的方法,因此在规则引擎位于远E服务器的情况下Q仍然可以用RuleExecutionSetProviderc,构造器的参数可以通过RMI来传递。另一个类是LocalRuleExecutionSetProviderQ包含了其他ҎQ用于从非Serializable资源Q如java.io.ReaderQ本地文Ӟ创徏RuleExectionSets。假设拥有了一个RuleServiceProvider对象Q你可以从本地文件rules.xml文g创徏一个RuleExectionSet对象。如以下的代码所C:<br>          RuleAdministrator admin = serviceProvider.getRuleAdministrator();<br>          HashMap properties = new HashMap();<br>          properties.put("name", "My Rules");<br>          properties.put("description", "A trivial rulebase");</div> <div>          FileReader reader = new FileReader("rules.xml");<br>          RuleExecutionSet ruleSet = null;<br>          try {<br>               LocalRuleExecutionSetProvider lresp =<br>               admin.getLocalRuleExecutionSetProvider(properties);</div> <div>               ruleSet = lresp.createRuleExecutionSet(reader, properties);<br>          } finally {<br>               reader.close();<br>          }<br>       接下来,你可以用RuleAdministrator注册获得的RuleExecutionSetQƈl它分配一个名U。在q行Ӟ你可以用同一个名U创Z个RuleSessionQ该RuleSession使用了这个命名的RuleExecutionSet。参见下面的例子Q?br>admin.registerRuleExecutionSet("rules", ruleSet, properties);</div> <div><br>  <strong>执行规则引擎</strong><br>       在运行时阶段Q你可以参见一个RuleSession对象。RuleSession对象基本上是一个装载了特定规则集合的规则引擎实例。你从RuleServiceProvider得到一个RuleRuntime对象Q接下来Q从javax.rules.RuleRuntime得到RuleSession对象?br>       RuleSession分ؓ两类Qstateful和stateless。它们具有不同的功能。StatefulRuleSession的Working Memory能够在多个方法调用期间保存状态。你可以在多个方法调用期间在Working Memory中加入多个对象,然后执行引擎Q接下来q可以加入更多的对象q再ơ执行引擎。相反,StatelessRuleSessioncL不保存状态的Qؓ了执行它的executeRulesҎQ你必须为Working Memory提供所有的初始数据Q执行规则引擎,得到一个内容列表作回倹{?br>       下面的例子中Q我们创Z个StatefulRuleSession实例Q添加两个对象(一个Integer和一个StringQ到Working MemoryQ执行规则,然后得到Working Memory中所有的内容Q作为java.util.List对象q回。最后,我们调用releaseҎ清理RuleSessionQ?br>         RuleRuntime runtime = rsp.getRuleRuntime();<br>         StatefulRuleSession session = (StatefulRuleSession)<br>         runtime.createRuleSession("rules", properties,<br>         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();</div> <div><br><strong>集成JSR 94产品实现<br></strong>       支持JSR 94规范的品实现既有收费的商业产品Q也有免费的开源项目。目前最为成熟,功能最强大的商业品是ILOG公司的JRulesQ该公司也是JSR 94规范的积极推动者之一。支持JSR 94规范的开源项目目前很,只有Drools和JLisa目。值得注意的是QJess不是开源项目,它可以免费用于学术研IӞ但用于商业用途则要收贏V?br><br>  <strong>JSR 94的品实?/strong><br>        Java规则引擎商业产品有:<br>           l. ILOG公司的JRules<br>          2. BlazeSoft公司的Blaze<br>          3. Rules4J<br>          4. Java Expert System Shell QJESSQ?br>        开源项目的实现包括Q?br>          l. Drools目</div> <div>         2. JLisa目<br>         3. OFBiz Rule EngineQ不支持JSR 94Q?br>         4. MandaraxQ目前不支持JSR 94Q?/div> <div><br>  <strong>使用Spring集成</strong><br>       集成Java规则引擎的目标是Q用标准的Java规则引擎API装不同的实玎ͼ屏蔽不同的品实现细节。这样做的好处是Q当替换不同的规则引擎品时Q可以不必修改应用代码?br>    <strong>装JSR94实现</strong></div> <div>       RuleEngineFacadecd装Java规则引擎Q用ruleServiceProviderUrl和ruleServiceProviderImpl两个参数Q屏蔽了不同产品的配|。代码如下:<br>       public class RuleEngineFacade {</div> <div>                private RuleAdministrator ruleAdministrator;<br>                private RuleServiceProvider ruleServiceProvider;<br>                private LocalRuleExecutionSetProvider ruleSetProvider;<br>                private RuleRuntime ruleRuntime;</div> <div>                // configuration parameters<br>                private String ruleServiceProviderUrl;<br>                private Class ruleServiceProviderImpl;<br> <br>          public void setRuleServiceProviderUrl(String url) {<br>                this.ruleServiceProviderUrl = url;<br>          }<br>           public void setRuleServiceProviderImpl(Class impl) {<br>                this.ruleServiceProviderImpl = impl;<br>          }<br>           public void init() throws Exception {<br>                RuleServiceProviderManager.registerRuleServiceProvider(<br>                ruleServiceProviderUrl, ruleServiceProviderImpl);</div> <div>                ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider(ruleServiceProviderUrl);</div> <div>                ruleAdministrator = ruleServiceProvider.getRuleAdministrator();<br>                ruleSetProvider = ruleAdministrator.getLocalRuleExecutionSetProvider(null);<br>          }</div> <div>          public void addRuleExecutionSet(String bindUri,InputStream resourceAsStream)<br>                    throws Exception {</div> <div>                Reader ruleReader = new InputStreamReader(resourceAsStream);<br>                RuleExecutionSet ruleExecutionSet =<br>                ruleSetProvider.createRuleExecutionSet(ruleReader, null);</div> <div>                ruleAdministrator.registerRuleExecutionSet(bindUri,ruleExecutionSet,null);<br>         }</div> <div>         public StatelessRuleSession getStatelessRuleSession(String key)<br>                   throws Exception {</div> <div>                ruleRuntime = ruleServiceProvider.getRuleRuntime();<br>                return (StatelessRuleSession) ruleRuntime.createRuleSession(key, null, RuleRuntime.STATELESS_SESSION_TYPE);<br>         }</div> <div>         public StatefulRuleSession getStatefulRuleSession(String key)<br>                   throws Exception {</div> <div>                ruleRuntime = ruleServiceProvider.getRuleRuntime();<br>                return (StatefulRuleSession) ruleRuntime.createRuleSession(<br>                key, null, RuleRuntime.STATEFUL_SESSION_TYPE);<br>         }</div> <div>         public RuleServiceProvider getRuleServiceProvider() {<br>                return this.ruleServiceProvider;<br>         }<br>    }</div> <div><br>    <strong>装规则<br></strong>        Rulecd装了具体的业务规则,它的输入参数ruleName是定义规则的配置文g名,q依赖于RuleEngineFacadelg。代码如下:<br>    public class Rule {</div> <div>         private String ruleName;<br>         private RuleEngineFacade engineFacade;<br> <br>         public void init() throws Exception {<br>              InputStream is = Rule.class.getResourceAsStream(ruleName);<br>              engineFacade.addRuleExecutionSet(ruleName, is);<br>              is.close();<br>        }<br> <br>        public void setRuleName(String name) {<br>             this.ruleName = name;<br>        }<br> <br>        public void setEngineFacade(RuleEngineFacade engine) {<br>            this.engineFacade = engine;<br>        }<br> <br>        public StatelessRuleSession getStatelessRuleSession()<br>                     throws Exception {<br>            return engineFacade.getStatelessRuleSession(ruleName);<br>        }<br> <br>        public StatefulRuleSession getStatefuleRuleSession()<br>                     throws Exception {<br>            return engineFacade.getStatefulRuleSession(ruleName);<br>        }<br>    }</div> <div><br>    <strong>l装规则lg</strong><br>       l装规则的配|文件如下:<br><bean id="ruleEngine" class="spring.RuleEngineFacade" init-method="init" singleton="false"><br>      <property name="ruleServiceProviderUrl"><br>           <value>http://drools.org/</value><br>      </property><br>      <property name="ruleServiceProviderImpl"><br>           <value>org.drools.jsr94.rules.RuleServiceProviderImpl</value><br>      </property><br></bean><br><bean id="fibonacci" class="spring.Rule" init-method="init"><br>      <property name="ruleName"><br>          <value>/test/fibonacci.drl</value><br>      </property><br>      <property name="engineFacade"><br>          <ref local="ruleEngine"/><br>      </property><br></bean></div> <div><br><strong>    试用例</strong><br>       最后,我们~写试用例Q代码如下:<br>public class JSRTest extends TestCase {</div> <div>      ApplicationContext ctx = null;</div> <div>      protected void setUp() throws Exception {<br>           super.setUp();<br>           ctx = new FileSystemXmlApplicationContext("testrule.xml");<br>      }<br>      public void testGetRuleSession() throws Exception {<br>           Rule rule = (Rule)ctx.getBean("fibonacci");<br>           assertNotNull(rule.getStatefuleRuleSession());<br>           assertNotNull(rule.getStatelessRuleSession());<br>      }<br>      public void testStatelessRule() throws Exception {<br>           Rule rule = (Rule)ctx.getBean("fibonacci");<br>           Fibonacci fibonacci = new Fibonacci(50);<br>           List list = new ArrayList();<br>           list.add(fibonacci);<br>           StatelessRuleSession session = rule.getStatelessRuleSession();<br>           session.executeRules(list);<br>           session.release();<br>      }<br>      public void testStatefulRule() throws Exception {<br>            Rule rule = (Rule)ctx.getBean("fibonacci");<br>            Fibonacci fibonacci = new Fibonacci(50);<br>            StatefulRuleSession session = rule.getStatefuleRuleSession();<br>            session.addObject(fibonacci);<br>            session.executeRules();<br>            session.release();<br>       }<br>}</div> <div> </div> <div>       q行试用例Q出现绿条,试通过?/div> <div><br><strong>规则定义语言之间的变?/strong><br>       因ؓJSR 94规范q没有强制统一规则定义的语法,因此Q当需要将应用UL到其他的Java规则引擎实现Ӟ可能需要变换规则定义,如将DroolsU有的DRL规则语言转换成标准的ruleMLQJess规则语言转换成ruleML{。这个工作一般由XSLT转换器来完成?/div> <br> <img src ="http://www.tkk7.com/junky/aggbug/126696.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/junky/" target="_blank">junky</a> 2007-06-28 08:57 <a href="http://www.tkk7.com/junky/archive/2007/06/28/126696.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>drools之helloworldhttp://www.tkk7.com/junky/archive/2007/06/28/126697.htmljunkyjunkyThu, 28 Jun 2007 00:57:00 GMThttp://www.tkk7.com/junky/archive/2007/06/28/126697.htmlhttp://www.tkk7.com/junky/comments/126697.htmlhttp://www.tkk7.com/junky/archive/2007/06/28/126697.html#Feedback0http://www.tkk7.com/junky/comments/commentRss/126697.htmlhttp://www.tkk7.com/junky/services/trackbacks/126697.html比如用OLAP支持复杂报表的快速定Ӟ用script语言如Groovy支持客户自定义公式,
q有Rule EngineQ我们一天到晚挂在口上的亲爱的商业规则?
Rule Engineq不新鲜Q但通常只要一些名词已l够把所有普通项目组震退QCLisp、Rete、前向推?... 惟有DroolsQ终于把java和xml带回我们w边Q让规则引擎单到和JSP一样可以进入所有的E序l?

先看一D늲又实用的HelloWorldQ由两部分组成, 一个是调用规则的test.jsp Q?

//讄一个测试用的VO
Vo vo = new Vo();
vo.setPoStatus("A:draft");

//d规则
RuleBase ruleBase = RuleBaseBuilder.buildFromURL("rule.drl");

//把vo攑օWorkingMemory中ƈ执行
WorkingMemory workingMemory = ruleBase.newWorkingMemory( );
workingMemory.assertObject( vo );
workingMemory.fireAllRules( );

//昄l果
out.print(po.getPoStatus());

一个是规则文grule.drlQ?

<rule-set name="test rules"
<rule name="Bob Likes Cheese">
<parameter identifier="vo">
<java:class>com.ito.vo</java:class>
</parameter>

<java:condition>vo.getStatus().equals("A:draft")</java:condition>

<java:consequence>
vo.setStatus("B:order");
</java:consequence>
</rule>
</rule-set>

整个规则分成三段Q?W一D定义刚刚放入的对象Q?W二D는Java语法判断条gQ?W三Dؓ条gW合时的执行语句
真的非常单吧


l过范围的试用Q发现没有这么简单,因ؓDrools主要提供了一个RETE的规则匹配算法和一个Script EngineQ具体怎么用,q很靠自己。如果drl文g的定义方式和RETE法能够使条件的表达大大化,那么它就是有用的。否则,一D重构后的代码能够达到和drl文g总的功能。所以,q是要多看点基础Q把Business Rules用在正确的地斏V?



提供一个eclipse的插?url: http://www.zymose.com/index.html


junky 2007-06-28 08:57 发表评论
]]>
Drools- 商务逻辑框架的选择http://www.tkk7.com/junky/archive/2007/06/27/126646.htmljunkyjunkyWed, 27 Jun 2007 10:16:00 GMThttp://www.tkk7.com/junky/archive/2007/06/27/126646.htmlhttp://www.tkk7.com/junky/comments/126646.htmlhttp://www.tkk7.com/junky/archive/2007/06/27/126646.html#Feedback0http://www.tkk7.com/junky/comments/commentRss/126646.htmlhttp://www.tkk7.com/junky/services/trackbacks/126646.html作者:保罗.布朗
译?greenbright





版权声明QQ何获得Matrix授权的网站,转蝲时请务必以超链接形式标明文章原始出处和作者信息及本声?/span>
作?保罗.布朗;greenbright
原文地址: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可以实现前端和后端的功能,但对于商务逻辑层却没有一个标准的构徏Ҏ。像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些规则的正与否?Ҏ术h员来_从来不关注商务h员)Q检查规则的正确性是非常困难的。那么,有什么方法论来测试商务逻辑那?
许多应用有着cM的商务逻辑。如果其中一个规则发生了变化Q我们能够确认所有系l中的相关部分都要改变吗Q如果一个新应用使用了一些规则,但是也加入了一些新规则Q我们需要彻底重写逻辑吗?
·        商务逻辑嵌入在Java代码中,每次哪怕是很小的改变都需要再~译/再部|这些代码,q些商务逻辑Ҏ配置?
·        如果其他的(脚本Q语a惛_^衡现有投资在商务规则逻辑中怎么办?

J2EE/EJB和倒置控制的框Ӟ像Spring, Pico和AvalonQ让我们有能力在高端l织代码。他们很提供很好的重用性,配置性和安全性,但却不能替代上面例子中的“意大利面条式代码”。理惛_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">if...then
形式来表辄事情。你从商务专安里听到的一些事情如?br>·        “10A表单用于甌过200Ƨ元的花?”
·        “我们仅对数量1万或过1万的交易提供分成.”
·        “过10m英镑的采购需要公司ȝ的批?”

通过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也扮演商务规则?#8220;模拟?#8220;-让我们说明输入,验输出;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所有hg?00Ƨ元的股。很昄Q没有数据类QStockOffer.javaQ和商务层类QBusinessLayer.javaQ这个测试用例是不能~译成功的?br>
清单2:
/**
*CZ商务逻辑的正?br>*q个单示例里Q所有的商务逻辑都包含在一个类中?br>*但在现实中,按需要代理给其他的类?br>*/
public class BusinessLayer {

        /**
   *评h购买q支股票是否是个好主?br>   *@参数 stockToBuy
   *@return 如果推荐购买股票q回真,否则q回?br>   */
  public static void evaluateStockPurchase
    (StockOffer stockToBuy){
                return false;
  }
}
StockOffercd下所C:
/**
* 单的JavaBean保存StockOffer倹{?br>* 一?#8217;股票Zh’是别h卖出股票Q公司股份)所l出的h根{?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;
  }
}


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

用规则描q商务逻辑

现在Q我们需要描qC些商务逻辑Q像“如果股票h低于100Ƨ元Q应该购买?#8221;
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是否购买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()Ҏ装蝲BusinessRules.drl文g中的规则?br>·        更新的evaluateStockPurchase()Ҏ评hq些商务规则。这个方法中需要注意的是:
·        同一个RuleSet可以被重复用(内存中的商务规则是无状态的Q?br>·        ׃以我们的知识我们知道什么是正确的,每次评h我们使用一个新的WorkingMemorycR在内存中用assertObject()Ҏ存放已知的实事(作ؓJava对象Q?br>·        Drools有一个事件侦听模式,能让我们“看到“事g模式内到底发生了什么事情。在q里我们用它打印试信息。Working memorycȝfireAllRules()Ҏ让规则被评h和更斎ͼ在这个例子中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正确Q测试通过。祝贺—你已经创徏了你的第一个基于规则的应用Q?br>
image
?。成功的Junit试

灉|的规?/span>

刚徏好系l,你示范了上面的原型给商务用户Q这时他们想起先前忘了给你提到几个规则了。新规则之一是当数量是负值时Q不能够交易股票。你?#8220;没问题,”Q然后回C的位,借可靠的知识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它于0也小?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。这是ؓ什么我们用单元测?模拟器:“辛苦?#8221;Junit试Q用通用Java代码Q保证规则引擎用我们x的行来做军_。(不要p上亿在一些无价值的股票上!Q同Ӟ规则引擎的强大和灉|性让我们能够q速开发商务逻辑?br>E后Q我们将看到更多冲突解决Ҏ的经典的方式?br>
冲突解决Ҏ

在商务这边,Z真的印象深刻q别开始通过可能的选择来思考。他们看到XYZ公司股票的问题ƈ且决定执行一条新规则:如果XYZ公司的股价低?0Ƨ元Q就仅仅买XYZ公司的股?br>象上ơ,加测试到模拟器中Q在规则文g中加入新的商务规则,如下所列。首先,在BusinessRuleTest.java中添加新Ҏ?br>
清单8:
/**
*保pȝpȝ在XYZ公司股h便宜时就购买他们的股?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达到的规则的条件。缺省的军_Ҏ如下Q?
·        显著?如上列出的我们分配的倹{?
·        崭新性:我们使用规则的次数?
·        复杂性:W一ơ触发的更复杂的特定规则?
·        装蝲序Q那个规则被装蝲的顺序?br>如果我们不说明这个例子中规则的显著性,会发生的是Q?
·        XYZ公司规则Q?#8220;如果股票h过10Ƨ元买XYZ”Q将被首先触发(推荐买标记的状态被|ؓNoQ?
·        然后是更多的普通规则被触发Q?#8220;买所有低?00的股?#8221;Q,推荐买标记的状态被|ؓyes?br>
q将得到我们不期望的l果。然而,我们的例子设|了显著性因素,用例及商务规则就会如我们期望的运行了?br>
大多数情况下Q书写清楚的规则且设|显著性将为Drools提供_的信息来选择触发规则的顺序。有Ӟ我们x个的改变解决规则冲突的方式。以下是一个如何改变的例子Q其中我告诉规则引擎首先触发最单的规则。要注意的是Q改变冲H解x案是要小心,因ؓ它能Ҏ的改变规则引擎的规则—用清楚的写得恰当的规则能预先解册多问题?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>

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

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

junky 2007-06-27 18:16 发表评论
]]>
在你的企业java应用中用Droolshttp://www.tkk7.com/junky/archive/2007/06/27/126645.htmljunkyjunkyWed, 27 Jun 2007 10:09:00 GMThttp://www.tkk7.com/junky/archive/2007/06/27/126645.htmlhttp://www.tkk7.com/junky/comments/126645.htmlhttp://www.tkk7.com/junky/archive/2007/06/27/126645.html#Feedback0http://www.tkk7.com/junky/comments/commentRss/126645.htmlhttp://www.tkk7.com/junky/services/trackbacks/126645.html版权声明Q可以Q意{载,转蝲时请务必以超链接形式标明文章原始出处和作者信息及本声?br>原文地址:
http://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?D|间企业Java直能让你睡着。有多少J2EE-EJB应用E序只是从网|取数据ƈ把它们存入到数据库中?但开发者真正应该开发和l护的却是他?应用E序中复杂的商业逻辑。这个问题不仅仅适用于将要新应用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中意味着现在你可?#8220;一路到?#8221;的用框架来构徏你的应用E序。图1昄了这L一个应?br>
image
?. 用于Java应用的框?br>
q篇文章基于我们已l了解的Drools框架的功能,q些功能可以让我们构L一个应用。]

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

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

我们到哪里了Q?/span>

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

?多数企业UJava应用是通过Web介面q行交互的,其中最被广泛用的Web表现层框架是Apache的Struts。理想的l果是:我们写的应用可以 从表现层知道它下面的应用?而不是通过相反的方向。它的好处在于不仅仅可以使我们将来变换其它的表现层(比如Ajax或web service界面Q,而且意味着CZ代码可以非常Ҏ地应用于其它像Spring的框架?br>
下面的代码片断演CZ始何从Web表现层调?商业逻辑Q通过规则引擎Q,q根据返回结果显CZ同的面。这一例子中,我们使用了一个Struts行ؓQ但其代码是和用其它表现层框架甚至一?Servlet或一个Jsp面是很cM的。这个片断用了struts-config.xml配置文gQJSP面来上?昄数据Qƈ且生成WAR?件来q行布v。片断展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Ҏ
   */
  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一例子中,需要注意我们将商业逻辑Q买或不C支股)与表现层逻辑Q决定{向哪一面Q分d来。这我们可以在不同的应用中重用我们的商业规则?另外Q看一下状态信息(用户已经告知我们的东西)是存储在Session中的StockOffer对象中的Qƈ没有在商业层中。这样就保证了商业层的无?态性,q将使整个应用更h展性和性能?br>
集成规则引擎与数据库?/span>

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

StockNameDao是一个定义了两个Ҏ的接口: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非数据源获取数据的Ҏ
*/
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)Ҏ
   */
  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Ҏ -->
  <!-- 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 -->    
  <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>?“股h_?#8221;的规则有一个新条gQ它用DaoFactory和StockNameDao来检查股是否在处理列表中?br>
?们又一ơ运行BusinessRulesTest(模拟?。模拟单元测试没有问题,既我们改变了程序的l构Q我们仍然没有改变它在做什么。从输出的日 志来看,我们可以看到我们的商业规则用StockNameDao作ؓ他们评估的一部䆾Qƈ?DaoImplementation.isOnStockList()被调用了?br>虽然q个例子展示的是从数据源d信息Q其实写信息也是一L?理。如果某个规则决定应该做的话。区别在于我们的DAO会有一些setSomeInformation()的方法,一旦条件满Iq个Ҏ会在商业规 则的<java:consequence>部分被调用?br>
ȝ
q?文章中Q我们展CZ大多数Java服务器端的应用有的三层:表现层,商业逻辑层和数据持久化层。当框架被广泛地使用在表现层和持久层中,直到目前为止q?没有框架可以包装低的商业逻辑。就像我们在q些例子中看的,Drools和JSR-94是降低java应用复杂度,提高开发速度的理惛_选者。我希望q?些例E能鼓励你去q一步接q规则引擎,他们会Z的应用的开发和l护节省不少旉?br>资源
?本文的范例代?/font>
?Drools目主页
?[ur=http://www.jroller.com/page/eu/20040810]Drools规则的信息[/url]
?"Introduction to Drools and Rule Engines," Drools目l提?/font>
?Drools规则的schema文g
?JSR-94: Java规则引擎概述
?Struts框架主页
?Spring框架主页
?Hibernate主页
?JUnit试框架
?
?[url=http://herzberg.ca.sandia.gov/jess/index.shtml]Jena语义与规则引?/font>

?JSR-94主页
?Jess in Action主页
?"Business Rule Thinking" (ZJess)
?a target=_new>规则pȝ的概q?/font>
?"Jess implementation of the Rete algorithm"

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


junky 2007-06-27 18:09 发表评论
]]>
վ֩ģ壺 ޹Ʒһڶҳ| һ| 99ƷƵ| ޾Ʒ| Ƶ| ʵƵѹۿ| ŷ ͼƬۺ| ĻƵ| ҹƷ| 鶹Ƶѹۿ| һ| ƵƷ| vva| ɫɫWWW| av| ҹav뾫Ʒ| ˳ɴƬ߹ۿŵӰ| ޾ƷA߹ۿ| 9ȾƷѹۿƵ| vvվ| AëƬav| þ޾ƷVA| ޻ɫ߹ۿ| ޾ƷƷԲվ | ޹Ʒһþ| ѹۿĻƷ| JLZZJLZZ| Ƶ߹ۿ| þƷAV鶹Ƭ| Ĺѹۿ߲ | 2021պƵ| ޸һƷ| պȫƵۿѹۿ| gayˬˬƵ| һֻ| AVѹۿ| һӰ| ѾƷ߶ | һ֮| 㽶Ƶ | ɫ͵͵Ů˵|