Drools使用手册第六--十章.doc_第1页
Drools使用手册第六--十章.doc_第2页
Drools使用手册第六--十章.doc_第3页
Drools使用手册第六--十章.doc_第4页
Drools使用手册第六--十章.doc_第5页
免费预览已结束,剩余31页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第六章. Java 规则引擎API6.1.简介Drools提供了一个Java规则引擎API(JSR94)的实现,它允许在一个API中支持多个规则引擎。JSR94不本身不对规则语言进行任何处理。WSC工作在Rule Interchange Format (RIF),而OMG则开始在RuleML的基础上建立一个标准,当前Haley系统已经提议一种规则语言标准称为RML。应当记住的是,JSR94标准描述了不同规则引擎特性的“最小公分母”,这个意思是说JSR94 API中的功能要比Drools API提供的功能要少。因此在JSR94中你不能应用Drools规则引擎的全部功能。Drools需要暴露出更多的功能,像全局变量,DRL、DSL支持,Xml属性映射等等,因为JSR94提供的功能集合是非常基本的特性。更进一步说,JSR94不提供一种规则语言,你只能使用规则引擎所提供的一小部分功能,能够获得的好处很有限。因此当我们为坚持使用JSR94的程序员提供API的同时,我们强烈建议使用Drools API。6.2.如何使用JSR94分为两部分工作。第一部分是管理API用来创建和注册RuleExecutionSet。第二部分是运行时Session,用来执行这些RuleExecutionSet。6.2.1.创建与注册RuleExecutionSetRuleServiceProviderManager对注册进行管理,并返回RuleServiceProvider。Drools的RuleServiceProvider实现在类被使用Class.forName装载时自动注册通过一个静态模块注册,在大多数情况下JDBC驱动也使用同样的方式。例6.1.自动注册RuleServiceProvider / RuleServiceProviderImpl通过一个静态初始化模块注册到 /Class.forName(org.drools.jsr94.rules.RuleServiceProviderImpl);/ 从提供者管理器中获得规则服务提供者RuleServiceProvider ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider(/);RuleServiceProvider提供对RuleRuntime和RuleAdministration 的API访问。RuleAdministration提供对RuleExecutionSet进行管理的API,使用该API可以注册一个RuleExecutionSet,然后可以用RuleRuntime来返回RuleExecutionSet。在RuleExecutionSet可以被注册前,你需要先建立它;RuleAdministrator提供工厂方法返回一个空的LocalRuleExecutionSetProvider或RuleExecutionSetProvider。LocalRuleExecutionSetProvider用来从不可以序列化的本地源中装载RuleExecutionSet,如数据流中。RuleExecutionSetProvider从可序列化的源中装载RuleExecutionSet,如DOM元素或包。ruleAdministrator.getLocalRuleExecutionSetProvider( null );和ruleAdministrator.getRuleExecutionSetProvider( null );都使用null作为参数,因为这些方法的属性映射当前不使用。例6.2.使用RuleAdministration API 注册 LocalRuleExecutionSet / 获得RuleAdministration RuleAdministration ruleAdministrator = ruleServiceProvider.getRuleAdministrator();LocalRuleExecutionSetProvider ruleExecutionSetProvider = ruleAdministrator.getLocalRuleExecutionSetProvider( null );/ 建立DRL读取器URL drlUrl = new URL(/sources/myrules.drl);Reader drlReader = new InputStreamReader( drlUrl.openStream() );/ 为DRL建立RuleExecutionSetRuleExecutionSet ruleExecutionSet = ruleExecutionSetProvider.createRuleExecutionSet( drlReader, null );在上例中ruleExecutionSetProvider.createRuleExecutionSet( reader, null )为属性映射提供了一个空参数;无论怎样,它实际上可以用来为引入的源提供配置。当Null传入时,默认装载的输入是DRL。允许为映射提供的关键字是source和dsl。Source使用drl或xml作为它的值,设置source为drl用来装载drl文件,设置为xml用来装载xml格式规则文件;xml将会忽略任何dsl键/值设置。Dsl可以获得一个读取流或一个字符串(包含dsl内容)作为值。例6.3.当注册LocalRuleExecutionSet 时指定DSL/ 获得 RuleAdministration RuleAdministration ruleAdministrator = ruleServiceProvider.getRuleAdministrator();LocalRuleExecutionSetProvider ruleExecutionSetProvider = ruleAdministrator.getLocalRuleExecutionSetProvider( null );/ 获得DRL读取流URL drlUrl = new URL(/sources/myrules.drl);Reader drlReader = new InputStreamReader( drlUrl.openStream() );/ 为dsl建立读取流,并放入属性映射中URL dslUrl = new URL(/sources/myrules.dsl);Reader dslReader = new InputStreamReader( dslUrl.openStream() );Map properties = new HashMap();properties.put( source, drl );properties.put( dsl, dslReader );/ 为drl和dsl建立 RuleExecutionSet RuleExecutionSet ruleExecutionSet = ruleExecutionSetProvider.createRuleExecutionSet( reader, properties );当注册RuleExecutionSet时必须指定名称,用于取回它。这也是一个输入属性的字段,当前没有使用它,因此输入空即可。When registering a RuleExecutionSet you must specify the name, to be used for its retrieval. There is also a field to pass properties, this is currently unused so just pass null.例6.4.Register the RuleExecutionSet/ 使用RuleAdministrator 注册RuleExecutionSet String uri = ruleExectionSet.getName();ruleAdministrator.registerRuleExecutionSet(uri, ruleExecutionSet, null);6.2.2.使用有状态和无状态RuleSession在运行时,RuleServiceProvider用来建立有状态或无状态的规则引擎Session。例6.5.获得RuleRuntimeRuleRuntime ruleRuntime = ruleServiceProvider.getRuleRuntime();为了建立规则Session,你必须使用RuleRuntime的两个公共常数之一,RuleRuntime.STATEFUL_SESSION_TYPE 和RuleRuntime.STATELESS_SESSION_TYPE,连同uri一起传入你希望初始化一个RuleSession的RuleExecutionSet中。属性映射可以是null,或者可以用来指定全局变量,这个在下一节说明。createRuleSession(.)方法返回一个RuleSession实例,它必须转义为StatefulRuleSession或StatelessRuleSession。例6.6.有状态规则(StatefulRuleSession) session = ruleRuntime.createRuleSession( uri, null, RuleRuntime.STATEFUL_SESSION_TYPE );session.addObject( new PurchaseOrder( lots of cheese ) );session.executeRules();StatelessRuleSession有一个非常简单的API,你只能调用executeRules(List list)传入对象列表,以及一个可选的过滤器,然后结果列表被返回。例6.7.无状态规则(StatelessRuleSession) session = ruleRuntime.createRuleSession( uri, null, RuleRuntime.STATELESS_SESSION_TYPE );List list = new ArrayList();list.add( new PurchaseOrder( even more cheese ) );List results = new ArrayList();results = session.executeRules( list );.全局变量通过使用属性映射传入RuleSession的工厂方法,JSR94可以通过使用一种非轻便的方式支持全局变量。全局变量必须定义在DRL或XML文件的开始,否则会抛出异常。属性映射的键为在drl或xml声明的变量名,值是你希望在执行中使用的值。在下例中结果被放在一个作为全局变量的java.util.List的集合中。java.util.List globalList = new java.util.ArrayList( );java.util.Map map = new java.util.HashMap( );map.put( list, globalList ); /打开无状态Session StatelessRuleSession srs = (StatelessRuleSession) runtime.createRuleSession( SistersRules, map, RuleRuntime.STATELESS_SESSION_TYPE );./ Person对象加入List/ 调用executeRules( ),将对象列表作为参数/ 规则将对象放入List/ 从映射中取得listList list = (java.util.List) map.get(list);不要忘记在你的DRL中声明list全局变量:package SistersRules; import org.drools.jsr94.rules.Person; global java.util.List listrule FindSisters when $person1 : Person ( $name1:name ) $person2 : Person ( $name2:name ) eval( $person1.hasSister($person2) ) then list.add($person1.getName() + and + $person2.getName() + are sisters); assert( $person1.getName() + and + $person2.getName() + are sisters); end6.3.参考书目如果你需要了解JSR 94的更多信息,请参考以下文章索引 1. Official JCP Specification for Java Rule Engine API (JSR 94) /en/jsr/detail?id=94 2. The Java Rule Engine API documentation /api_doc/api/index.html 3. The Logic From The Bottom Line: An Introduction to The Drools Project. By N. Alex Rupp, published on TheServiceS in 2004 /articles/article.tss?l=Drools 4. Getting Started With the Java Rule Engine API (JSR 94): Toward Rule-Based Applications. By Dr. Qusay H. Mahmoud, published on Sun Developer Network in 2005 /developer/technicalArticles/J2SE/JavaRule.html 5. Jess and the javax.rules API. By Ernest Friedman-Hill, published on TheServerS in 2003 /articles/article.tss?l=Jess 第7章.性能调整7.1.性能考虑在任何复杂的应用中,许多事情可能会对性能造成影响。通常的建议是不要随意估测,准确度量,剖析和计划。在规则引擎方面,不用考虑,它当然会尽可能的达到最好的执行效率。大多数人不需要关注这章的细节。注意,当程序员第一次使用规则引擎时,最应当注意的“花费”应当是规则引擎的启动(它将编译规则)。这个问题很容易解决,将RuleBase(或已编译好的RulePackage)实例缓存起来,并且仅仅只更新需要的规则(在应用中有许多方法可以实现它,这里不再讨论)。这章主要是考虑规则在运行时的执行效率的调整,而不是编译时,这是性能通常被真正监测的地方。7.1.1.Beta Node Memory Indexing(节点内存索引)在Rete算法章节提到,BetaNode是有两个输入的节点:左输入(组元)和右输入(单个对象)。每一个BetaNode有两个内存,每一个输入有一个:左输入内存和右输入内存。因此,当单个对象进入节点的右输入时,它尝试对左输入内存中的每一个组元进行匹配,以找到满足BetaNode的约束。这些匹配的元素通过网络向下传播。当一个组元达到左输入节点时,对称的行为发生。如下图所示:图7.1.Beta Node当在BetaNode内存中的元素数量越来越多时,匹配过程开始变慢,因为每一个到达的新元素需要为给定的约束在相对的内存中尝试匹配所有元素。当数千个Fact被设置到working memory中时,这将变成一个严重的限制。解决问题的一个方法是在元素到达BetaNode内存时对元素进行索引,这样不需要为了发现匹配而遍历相对内存中的所有元素。示例,如果有如下规则: rule find brothers when p1: Person( $mother : mother ) p2: Person( mother = $mother ) then / do somethingend如果没有使用索引,每一个设置到working memory中的Person对象将尝试匹配之前设置进来的所有Person对象,查看是否有同样的mother。因此如果之前已经有1000个Person对象在working memory中,如果我们再设置进来一个新的Person对象,它需要与之前的Person对象进行1000次匹配。如果我们使用“mother”属性对BetaNode内存进行索引,当新的一个Person对象设置到内存时,它只需要匹配之前有相同mother属性的对象(有相同mother属性的可能不只是Person对象,因此要进行匹配)就行了,通过索引可以非常高效率的完成这个过程。经过索引,如果在一个新的Person对象之前只有他的一个兄弟Person对象存在,则它只要匹配这一个对象就行了,避免了其它999次失败尝试。Drools正如上面所说的实现了对BetaNode的索引,以提高性能。BetaNode索引是默认启用的,用户通常不需要去担心它。虽然,在某些特殊情况下,用户可能受限于系统内存或其它原因不想启用索引功能,索引可以单独在各内存上被禁止,通过设置如下的系统属性:org.drools.reteoo.beta.index-leftorg.drools.reteoo.beta.index-right例:.当你在启动应用时-Dorg.drools.reteoo.beta.index-right=false-Dorg.drools.reteoo.beta.index-left=false7.1.2.索引性能调整理解当索引启用时发生了什么的一个好办法是分析数据库系统。众所周知,索引是非常重要的提升数据库查询性能的机制,但是也增加了在insert、update和delete这样的操作时的负担。另外,也会引起内存的消耗。对于大多数企业应用来说一个计划良好索引编排是基本要求,这通常是数据库管理员的责任。一旦所以被定义,当查询被执行后,一个查询计划组件被数据库系统用来评估运行该查询的最佳性能的办法,有时使用索引,有时不用。Working memory在这点上有着同样的问题和同样的思路。Drools实现一个自动的索引策略来建立BetaNode内存的索引。为了通过一些数据让我们可以更好的理解它,将使用“Manners 64 benchmark”测试用例在“Pentium IV 3 Ghz HT 1GB memory”的机器上的执行情况来说明问题。这里的并不是一个详细的基准测试,只是一些简单的概括,使得你更容易理解。Manners 64 无索引: 135000 毫秒运行时间 Manners 64 使用BetaNode 索引: 10078 毫秒运行时间显然在建立索引上花费的时间远远小于为运行时带来的性能收益。这里我们不分析内存受限环境。每个系统有它自己的特性,有时候它可能可以对性能作出更好的调整。例如在“Manners 64 example”测试中,如果我们关闭右输入内存索引,我们可以获得下面的结果Manners 64 仅使用BetaNode左输入内存索引: 142000 毫秒运行时间以上甚至比不使用索引更糟糕。发生这种情况的原因在Manners 64中很容易看出,左输入索引的消耗大于可以获得的好处。因此如果我们反过来,启用右输入索引而关闭左输入索引,我们获得下面结果:Manners 64仅使用BetaNode右输入内存索引: 8765毫秒运行时间现在我们获得了最佳效果。对于Manners 64来说,最佳方案是关闭左索引,保留右索引。.重新安排约束条件顺序另一个提高性能办法的提示是,当编写规则时,尽量将严格的约束条件放在相对不严格的约束条件前面。例如,如果有如下规则约束:Employee (department = $aDepartment, name = $aName)将name放在department前面会带来更好的效率,因为name的约束条件更加严格。Employee (name = $aName, department = $aDepartment)(除非你工作在一个部门比人员更多的组织中,这时可以考虑将department放在前面)另一些增强正在被开发,将在未来版本中进行说明。7.1.3.大型Ruleset对于本节,巨大的RuleSet定义如下: 1-500 小型ruleset 500-2000 中型ruleset 2000+ - 大型ruleset 10,000 巨大型ruleset 在某些情况下,规则引擎不得不处理超过50万或100万条规则。这些情况是在智能AI系统中,其中的规则引擎在执行时将产生新的规则,术语和Fact。这些讨论超越了本文档考虑范围。当前描述主要集中在商业规则上。第一件事情是考虑为什么有如此多规则,是否可以通过重写规则来解决问题。有很多问题可以寻找。 是否规则有很多常量值被硬编码在条件中 是否域模型有一个超过100列的巨大电子表格 是否绝大多数规则共享相同条件 是否逻辑可以被分解到不同阶段 如果你对这4个问题的任何一个可以给出肯定答复,那也许有机会通过改变规则来解决问题。管理100,000甚至1,000,000规则是非常让人头疼的,尽量避免它。检查规则,并看看是否向下面例子所示。If customer.account = abcd customer.type = basic .Then / do something 上面规则示例的基本问题是,规则有太多硬编码值。如果每个客户平均有50个规则,4万客户就会有200万条规则。让我们使用更具体的例子说明:If customer.accountId = peter customer.type = level2 customer.favoriateActor = jackie chanThen recommend movies with jackie chanIf customer.accountId = peter customer.type = level2 customer.favoriateActor = jet liThen recommend movies with jet li 查看示例,第一个问题是“这些规则是否应用到所有Customer”,如果确认是,则规则中的第一个条件customer.accountId是无意义的。因为所有的规则的这个类型都有该条件。虽然accountId更改了,规则可以有效地忽略它。如果我们在这重写规则,规则可以用来支持任何客户像jackie chan 和jet li。If customer.type = level2 customer.favoriateActor = jackie chanThen recommend movies with jackie chanIf customer.type = level2 customer.favoriateActor = jet liThen recommend movies with jet li 我们这样做的原因一目了然。在规则中包含客户的accountId硬编码没有任何好处,因为我们只希望规则引擎评估激活的部分。我们不希望将所有Customer都装载到规则引擎中。接下来我们更进一步,让规则更加通用化。If customer.type = level2 customer.accountId ?id / 绑定customer.accountId到变量 favorites.accountId ?id / 通过绑定变量查找favorites 的列表Then recommend all items in the favorites通过这样的改变,能够显著的减少规则的数量。这也是Rete路径通常被称为“数据驱动路径”的原因之一。让我们在这个示例上更进一步,定义customer的type属性从level1 到 level10。假设我们运行一个百万级的在线商店,客户可以在每一个分类(书,影碟,音乐,玩具,电子产品,服装等等)中定义他们自己的喜好。如果对每一个客户在分类中有不同的级别,会发生什么事情?如果使用硬编码,将不得不增加更多的规则。如果我们改变规则,使它更具有通用性,同样的规则可以处理多个分类。Say we run a mega online store and customers can define their favorites in each of the categories (books, videos, music, toys, electronics, clothing). What happens if a customer has different levels for each category. Using the hard coded approach, one might have to add more rules. If we change the rule and make it more generalized, the same rule can handle multiple categories.If recommendation.level ?lvl / 绑定recommendation level到lvl变量 recommendation.category ?rcat / 绑定recommendation category到rcat customer.accountId ?id / 绑定account id到id favorites.accountId ?id / 通过id找到favorites列表 favorites.category ?rcat / 将favorite匹配到recommendation category favorites.level ?lvl / 匹配favorite level到recommendation levelThen recommend all items in the favorites 如此看来,使规则具有动态性,并由数据驱动的价值在哪里呢?显然,硬编码规则要比让规则具有通用性更快,但是会影响性能。在ruleset较小的例子中,使用,使用硬编码可能对性能有轻微的提高。为什么会这样?让我们看一下两种不同的规则引擎:流程型(procedural)和Rete算法型在一个流程型引擎中,一旦数据无法满足在给定级别上的条件,引擎可以建立一个决策树并且结束评估。当规则数量增加时,流程引擎有许多的规则需要评估。在一个程序路径上,规则必须按照最佳的顺序排列,以获得最好的结果。最佳顺序排列方法的限制是,许多情况下无法对规则进行预先排序。如果我们使用一个RETE规则引擎,硬编码的规则导致与少数规则更少的关联。当规则数量增加时,单个规则的执行更佳。通过对两者评估,可以得到通用性的规则比硬编码常量规则的速度更快。译者注:上面这段翻译后不能清晰理解其含义,因此保留原文对照。In a procedural engine, one can build a decision tree and end the evaluation once the data fails to satisfy the conditions at a given level. As the rule count increases, there are more rules the engine has to evaluate. In a procedural approach, the rules have to be sequenced in the optimal order to get the best results. The limitation of sorting the rules in optimal sequence is that many cases its not possible to pre-sort. If we use a RETE rule engine, the hard coded rules result in fewer joins for a small number of rules. As the rule count grows, the single rule will perform better. The equation to estimate the threshold where the generalized form is faster than hard coding the constants.bn = 关联节点, lf = left facts, rf = right facts, ae = 对于随机样本的对象类型节点进行递减评估的平均数译者注:原文如下average number of evaluation descending from the object type node for a random sample, f = facts, hd = 规则中的硬编码常量, general = 通用格式使用的连接数general( sum( bn(lf * rf) ) + sum(ae * f) ) hd( sum( bn(lf * rf) ) + sum(ae * f) )对这两种方式的最佳量化方法是通过两种方式编写规则,并运行系列测试。大多数项目有严格的计划,开发者通常不可能有时间这样做。另一个常见问题是使用了大量的扁平化对象。简单地说,在规则中使用大量的扁平对象导致与硬编码常数同样的问题。对于这个问题的解决方案是改变域对象,能够以一种更简洁的方式表达商业模型。这个方法不一定每次都能适用。当大多数规则共享同样的条件时,有两种解决方案。最好的办法是使用链接重写规则。识别常用条件,并将它选取到通用的规则中。通用的规则通过设置一个新的fact触发后来的规则。通常这样可以将规则减少一个数量级或更多。第二种方法是将通用条件放在规则的开始部分。这样可以允许RETE规则引擎共享这些节点。当节点被共享后,它将减少内存的占用,并提升性能。如果RuleSet可以被分成更小的块,将ruleset分为离散的块,放在不同的JVM或服务器上运行是一个好办法。这个办法依赖于环境是否允许。那在ruleset规模过大,重写规则又不可行时还有什么办法呢?仅有的办法是扩展硬件并使用一个不同的JVM。这意味着使用64位JVM在一台至少8GB内存的机器上。依赖于ruleset的情况,系统可能需要更多内存。第8章.示例8.1.获得示例在Drools源代码中一些示例被当作集成测试包含。另外,你可以下载drools-examples模块,这是一个自包含的Eclipse项目。这个模块中有许多例子。项目地址:/labs/jbossrules/trunk/drools-examples/ 第9章.部署与测试9.1.部署选项一旦将规则集成在你的应用中,你需要激活如何将规则与你的应用一起部署。规则的特点是用来允许应用程序的改变而不用重新部署整个应用。这意味着规则必须作为应用的数据提供,而不是应用的部分(如嵌入classpath中)。Drools3.0规则引擎为规则部署开放了很多选项。这章的主要焦点在部署选项和API上。Drools的未来版本将会有一个规则服务器组件,用来管理规则的多个版本(包括锁定和自动部署)。因为每个组织都有不同,因此需要不同的部署模式。许多组织对于产品线的更改有配置管理流程。从这方面考虑,最好将规则考虑为数据而不是软件。但是,因为规则可以包含相当多的强大的逻辑,应当使用正确的测试、确认流程来控制规则的改变,在将规则发布出去之前要确认它们正确。9.1.1.可发布对象RuleBase, Package 等在最简单的情况下,你可以编译和构造一个rulebase,然后缓存这个rulebase。这个rulebase可以被线程共享,每个线程中产生新的working memory来处理事务(然后working memory被抛弃)。这本质上是一个无状态模式。为了更新rulebase,需要重新装载一个新的rulebase,然后交换出缓存的rulebase(任何正在使用旧的rulebase的线程可以继续使用直到结束,在这个情况下rulebase最终会被垃圾处理器收集)。可以有许多更灵巧的办法实现上面的案例,Drools规则引擎十分的动态,意味着许多组件能够被动态交换(rules,packages)甚至有working memory正在使用的时候。例如说,规则可以从一个有许多使用中的working memory的rulebase中删除,RETE网络将自动调整以删除该规则而不需要将其它fact重新设置一次。长期运行的working memory对于复杂的应用来说是很有用的,规则引擎随时增加库中的知识,用来对实际情况进行辅助决策(在这些例子中,展现了引擎的动态特性)。.DRL 和PackageDescr一种办法是将规则部署为源码格式。这种办法依赖于运行时引擎(必需包含编译器组件)去编译规则,并建立rulebase。一个类似的方法是部署PackageDescr对象,这意味着规则被预先解析好(对语法错误),但是没有被编译成二进制格式。使用PackageBuilder类完成编译。如果需要,你当然也可以使用XML格式的规则。PackageDescr, PackageBuilder, RuleBaseLoader.Package这种方法最具有灵活性。在这种情况下,使用PackageBuilder从DRL源码建立Package,但是它是可以被部署的二进制Package对象。多个Package可以被合并在一起。这意味着package可能包含一个单独的新规则,或对现有规则的更改;可以建立这样的package然后与在RuleBase中的现有package合并。RuleBase然后就能统治working memory新的规则的存在(因为RuleBase保存着对由它产生的working memory的弱引用)。RuleBase保存着Package的列表,并且合并到其中一个Package,你需要知道哪一个是你需要合并的Package(显然,只有在同样包名中的规则可以被合并)。Package对象是可以序列化的,因此它们可以在网络上发送,或绑定到JNDI,Session等等。PackageBuilder, RuleBase, org.drools.rule.Package.RuleBase编译好的Package被加入RuleBase。RuleBase是可序列化的,因此它们能够被当作二进制部署单元。当RuleBase被整体更新时,这是一个有用的选项,对短期存在的working memory。如果存在的Working Memory需要动态改变规则,最好还是部署Package对象。RuleBase, RuleBaseLoader.Serializing 序列化事实上在Drools中所有与RuleBase有联系的对象都是可序列化的。为了让WorkingMemory可序列化,你设置的所有对象也必须可序列化。因此它通常可以进行远程发布,并且绑定规则到JNDI中,就像在容器中使用它们一样。译者注:这句翻译的意思不太理解,提供原文 So it is always possible to deploy remotely, and bind rule assets to JNDI as a means of using them in a container environment.请注意,当使用Package Builder时,在继续发布你的规则之前,你可能希望检查hasError标记。如果存在错误,你可以从Package Builder中获得它们,好过在部署的时候才发现问题。9.1.2.部署模式.进程内规则构建在这种情况下,规则以源码方式提供到运行时系统。系统包含drools-compiler规则编译器组件构建规则。这是最简单的方式。.进程外规则构建在这种情况下,规则在运行时系统外被构建成二进制格式(例如在一个部署服务器中)。进程外构建的主要好处是,运行时系统可以最少的依赖运行规则所需的库(只有一个jar)。它也意味着所有编译错误可以在部署到运行系统前获得并处理。在进程外使用PackageBuilder类,然后使用getPackage()获得Package对象。你接着可以序列化Package到一个文件(使用java标准序列化)。运行时系统只需要drools-core库引用,就可以使用RuleBaseFactory.newRuleBase().addPackage(deserialized package object)载入该文件。.一些部署方法这节包含一些部署的建议。当然你可以使用不同的技术去完成。.1.Pull 拉风格在这种方法中,规则从规则库中被拉到运行系统中。规则库可以是一个简单的文件系统,或是一个数据库。拉规则的触发器可以是一个定时任务(检查变更),或一个发到运行时系统的请求(可能使用JMX接口)。这可能是最常用的方式。.2.Push 推风格在这种方式中,规则部署进程/规则库推规则到运行系统中(规则可能是源码或二进制格式)。当新的规则生效时,这可以给与更多的控制。9.1.3.Web Services一种发布规则的可能方式是将规则暴露为Web服务。有很多方法完成,但是目前最简单的一种方法是使用一个接口优先的进程:定义将在XML Schema中使用的fact类/模板,然后使用绑定技术产生这些与实际操作对应的规则的绑定对象。一种相反的可能是使用XSD/WSDL产生器产生对这些处理构建的类(操作对应的规则)的XML绑定。希望在将来的版本中,可以有一种自动的工具将规则暴露为Web服务(可能使用XSD作为fact来给规则操作)。9.1.4.未来的期望Drools的将来版本将提供一个规则库组件,将直接支持以上的摸式,以及更多。9.2.测试在这些年,测试驱动开发成为了主流,作为这种技术带给软件开发的价值已经被确认。在某方面来说,规则是编码(虽然在更高的级别),测试驱动开发的许多原则同样适用。你可以在规则编写前提供测试来规定规则的行为。更进一步说,测试在规则频繁变动的环境下,比规则更重要。测试可以提供一个信心底线,规则的改变是否与系统相容,可以从测试中了解。当然,规则的改变也可能就是会引起测试的错误,这种情况下需要编写新的测试来覆盖新的规则行为。在测试驱动开发的方式中,测试需要经常运行,在一个规则驱动的环境中,这意味着每次规则改变都应该运行测试(甚至软件本身没有任何变化)。9.2.1.测试框架对应程序员来说,Junit(或TestNG)是开发测试代码的常用工具,它们也可以用来测试规则。记住,规则的变更可能超过测试代码的范围,因此你应该随时将测试单元保持与规则的更新同步(在某些环境中可能是无法实现的)。当然,最好的想法是让测试关注规则的核心特性,这样就不需要随时改变。显然,对于规则测试,其它非源代码驱动的架构在某些环境下也可以用来测试规则。下一节介绍了一个规则测试组件。9.2.2.规则的集成测试框架作为一个独立附件,有一个测试架构建立在FIT(集成测试架构)上。它允许

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论