第 8章 规则和流程 Drools流是一个工作流和流程的引擎,它允许高度集成流程和规则。本章讨论规则和流程的集成,从简单方案到高级方案。 纯 粹依赖流程结构(如节点和线路)描述应用程序业务逻辑的工作流(Workflow)语言往往是相当复杂。尽管这些工作流结构很适合于描述一个应用程序的整 个控制流,但是描述复杂逻辑和特殊情况却相当困难。因此,可执行的流程往往变得非常复杂。我们相信,通过扩展流程引擎,支持声明式规则与这些标准流程结构 的结合,这种复杂性可以得到控制。
工 作流语言描述了使用一个流程图时应该被执行的活动的顺序。流程引擎负责根据执行流程的当前状态选择应该执行的活动。另一方面,规则是由描述什么时候可以应 用一条规则的一组条件和在条件满足时被执行的一个动作构成。然后规则引擎负责计算和执行规则。它根据应用程序的当前状态决定需要被执行的规则。 工作流流程擅长于描述应用程序的整个控制流(可能是长期运行的)。然而,流程被用于定义复杂的业务决策,要处理许多特殊情况,和需要响应各种外面事件,实事上往往变得非常复杂。规则擅长于描述复杂的决策和大量数据或事件的推理。但是不常使用规则来定义长期运行流程。 在过去,用户被迫在使用流程或规则引擎定义他们的业务逻辑两者间做选择。关于大量数据需要推理的问题使用规则引擎,而用户想关注描述他们流程的控制流则被迫使用流程引擎。然而,如今的业务可能希望合并流程和规则,以便于他们能够以最适合的格式定义他们所有的业务逻辑。 基 本上,规则和流程引擎通过查看它的知识库(一组规则或流程,各自的)和应用程序的当前已经状态(在工作内存中的数据或执行流程的状态,各自的)得到需要被 执行的下一个步骤。如果我们希望集成规则和流程,我们需要一个引擎,它可以就在流程和规则两个内部定义的逻辑决定下一个步骤。 扩 展流程引擎,还把规则考虑在内是非常困难(也可能是非常低效的)。流程引擎需要检查在每一步都需要执行的规则,并且必须保持规则引擎使用的最新数据。然 而,“教给”规则引擎有关流程是不困难的。如果当前的流程状态也被作为工作内存有关规则引擎推理数据的一部分插入,并且我们指示规则引擎如何得到一个执行 流程的下一个步骤,那么规则引擎将能够得到把规则和流程联合考虑的下一个步骤。 从流程的观点看,这意味存在有一个控制反转。常规的流程引擎行使完全控制,根据流程实例的当前状态得到下一个步骤。如果需要,它能够联系外部服务,检索附加信息,但是它独自决定要采取的步骤,并单独负责执行这些步骤。 然 而,只有我们扩展规则引擎(它能够联合规则和引擎推理)才能得到把规则和流程两个联合考虑的下一个步骤。如果需要执行流程的一部分,规则引擎会请求流程引 擎执行这个步骤。 一旦这个步骤已经执行,流程引擎返回控制给规则引擎,再得到下一个步骤。这意味着下一步该做什么已经被反转:流程引擎自身不再决定要获得的下一个步骤,但 是我们增加的规则引擎会控制、通知流程引擎在什么时候执行什么东西。 drools-examples项目包含了一个样本流程(org.drools.examples.process.order),用于说明合并流程和规则的一些优势。 这个流程描述了一个订单应用程序,校验进入的订单、计算折扣和申请货物航运。 Drools流可以轻松地包括一组规则作为流程的一部分。需要被计算的规则,应该使用ruleflow-group规则属性,分组在一个规则流组中。 rule "Invalid item id" ruleflow-group "validate" lock-on-active true when o: Order() i: Order.OrderItem() from o.getOrderItems() not (Item() from itemCatalog.getItem(i.getItemId())) then System.err.println("Invalid item id found!"); o.addError("Invalid item id " + i.getItemId()); end
图8.1. RuleSet节点和它的规则之一 可 以在你的流程中使用规则表达和计算复杂约束。例如,在一个Split节点决定执行路径的选择时,可以使用规则来定义这些条件。相似的,一个 Wait 状态可用一条规则来定义等待期限。这个例子使用规则决定在验证订单后的下一个动作。如果订单包含错误,一个销售代表应该尝试修正订单。订单的价格> 1000$ 是更重要的,那么一个高级代表应该照料该订单。所有其他订单只应该正常处理。 一个决定节点被用于选取这些选择之一,并且规则被用来描述它们每一个的约 束。 可以在一个流程中使用人类(Human)任务,描述需要由人类参与者执行的工作。 可以根据流程的当前状态和历史选择参与者。分配规则描述了如何根据这些信息决定参与者。每当一个新的人类任务需要被执行,那么这些分配规则会被自动应用。 注意,显示在下面的规则是用域特殊语言( Domain Specific Language -DSL)编写,针对在订单处理环境中的具体要求制定条件。 /********** Generic assignment rules **********/ rule "Assign 'Correct Order' to any sales representative" salience 30 when There is a human task - with task name "Correct Order" - without actor id then Set actor id "Sales Representative" end /********** Assignment rules for the RuleSetExample process **********/ rule "Assign 'Follow-up Order' to a senior sales representative" salience 40 when Process "org.drools.examples.process.ruleset.RuleSetExample" contains a human task - with task name "Follow-up Order" - without actor id then Set actor id "Senior Sales Representative" end 规则可以被用来描述特殊情况,以及如何响应这些特殊情况。在正规流程的控制流中添加所有这些信息使基本流程变得更复杂。规则可以被用来分别处理各个这些情况,使核心流程保持简单的格式。它也使它更容易适合现有的流程考虑先前未曾预料的事件。 流 程定义了整个控制流。规则可以被用来为这个流程添加附加关注点,不必使整个控制流更复杂。例如,规则可以被用来记录在流程执行期间的某些信息。不改变原始 流程,而所有日志功能作为一组规则被清楚地模块化。这极大地改善可重用性(允许用户轻松地对不同的流程应用相同的策略)、可读性(不改变原始流程的控制 流)和可维护性(由于日志策略规则从那些流程本身的分离)。 8.4.6. 规则用于动态改变流程行为 规 则让你动态地细调你的规则的行为。假设在运行期间有一个流程遭遇了一个问题。现在,在运行期间,可以添加新规则,记录附加信息或者处理特定流程的状态。一 旦问题被解决或者环境已经改变,这些规则可以轻松地再次被删除。根据当前状态,可以动态地选择不同的策略。例如,根据当前加载的所有服务,规则可以被用于 为当前加载优化流程。这个流程包含了一个简单例子,允许你为 "Check Order"任务动态地增加或删除日志。当在主应用程序窗口中的"Debugging output"复选框被选取,只要"Check Order"任务被请求,规则显示下面的动态加载,写记录输出到控制台。取消该框的选取,将动态地再次删除规则 rule "Log the execution of 'Correct Order'" salience 25 when workItemNodeInstance: WorkItemNodeInstance( workItemId <= 0, node.name == "Correct Order" ) workItem: WorkItemImpl( state == WorkItemImpl.PENDING ) from workItemNodeInstance.getWorkItem() then ProcessInstance proc = workItemNodeInstance.getProcessInstance(); VariableScopeInstance variableScopeInstance = (VariableScopeInstance)proc.getContextInstance( VariableScope.VARIABLE_SCOPE ); System.out.println( "LOGGING: Requesting the correction of " + variableScopeInstance.getVariable("order")); end 8.4.7. 集成工具 在Drools Eclipse IDE中集成了流程和规则。 流程和规则被简单地看作业务逻辑的不同类型,管理几乎是相同的。例如,加载一个流程或一组规则到引擎是非常相似的。另外,不同规则的实现,如DRL或 DSL,都以统一的方式被处理。 private static KnowledgeBase createKnowledgeBase() throws Exception { KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kbuilder.add( ResourceFactory.newClassPathResource( "RuleSetExample.rf", OrderExample.class), ResourceType.DRF ); kbuilder.add( ResourceFactory.newClassPathResource( "workflow_rules.drl", OrderExample.class), ResourceType.DRL ); kbuilder.add( ResourceFactory.newClassPathResource( "assignment.dsl", OrderExample.class), ResourceType.DSL ); kbuilder.add( ResourceFactory.newClassPathResource( "assignment.dslr", OrderExample.class), ResourceType.DSLR ); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() ); return kbase; }
我们的审计日志也包含一个集成视图,显示规则和流程序是如何相互影响。例如,日志的一部分,显示了规则"5% discount" 如何被作为节点"Calculate Discount"的部分被执行。 定义规则不需要使用核心规则语言的语法,而定义它们还可以使用我们更高级的规则编辑器,使用域特殊语言,决定表,向导编辑器等等。我们的例子定义了一个域特殊语言,用于根据任务的类型、它的属性、定义它的流程等等描述分配规则。这使分配规则让非专家人士更好理解。 /********** Generic assignment rules **********/ rule "Assign 'Correct Order' to any sales representative" salience 30 when There is a human task - with task name "Correct Order" - without actor id then Set actor id "Sales Representative" end
/********** Assignment rules for the RuleSetExample process **********/ rule "Assign 'Follow-up Order' to a senior sales representative" salience 40 when Process "org.drools.examples.process.ruleset.RuleSetExample" contains a human task - with task name "Follow-up Order" - without actor id then Set actor id "Senior Sales Representative" end |
|