Drools 规 则 引 擎 在 实 现 业 务 逻 辑 中 的 应 用 刘 际 赵 广 利 大 连 海 事 大 学, 大 连 (116026) E-mail:henterji@gmail.com 摘 要 : 现 今, 企 业 级 java 应 用 中 的 业 务 逻 辑 越 来 越 复 杂, 而 这 些 复 杂 的 业 务 逻 辑 又 广 泛 的 分 布 在 应 用 程 序 中 无 论 是 软 件 的 开 发 或 是 软 件 的 维 护, 花 费 的 成 本 都 非 常 高, 且 软 件 开 发 的 难 度 将 越 来 越 大 而 规 则 引 擎 可 以 通 过 将 业 务 规 则 集 中 管 理 来 降 低 实 现 复 杂 业 务 逻 辑 的 组 件 的 复 杂 性, 同 时 降 低 应 用 程 序 的 维 护 和 可 扩 展 性 成 本 本 文 阐 述 了 如 何 使 用 Drools 规 则 引 擎 使 Java 应 用 程 序 的 开 发 更 能 适 应 用 户 需 求 变 化, 降 低 软 件 开 发 的 复 杂 度 关 键 词 :Drools, 规 则 引 擎, 业 务 逻 辑 1. 引 言 要 求 施 加 在 当 今 软 件 产 品 上 的 大 多 数 复 杂 性 是 行 为 和 功 能 方 面 的, 从 而 导 致 组 件 实 现 具 有 复 杂 的 业 务 逻 辑 企 业 级 Java 应 用 中 业 务 逻 辑 最 常 见 的 方 法 是 编 写 Java 代 码 来 实 现 需 求 文 档 的 规 则 和 逻 辑 在 大 多 数 情 况 下, 代 码 的 错 综 复 杂 性 使 得 维 护 和 更 新 应 用 程 序 的 业 务 逻 辑 成 为 一 项 令 人 畏 惧 的 任 务, 甚 至 对 于 经 验 丰 富 的 开 发 人 员 来 说 也 是 如 此 业 务 逻 辑 需 求 的 任 何 更 改, 不 管 多 么 简 单, 仍 然 会 产 生 重 编 译 和 重 部 署 的 成 本 而 与 此 同 时, 出 于 以 下 原 因, 实 现 应 用 程 序 业 务 逻 辑 的 组 件 可 能 必 须 更 改 [4] : (1) 在 开 发 期 间 或 部 署 后 修 复 代 码 缺 陷 ; (2) 应 付 特 殊 状 况, 即 客 户 一 开 始 没 有 考 虑 到 的 业 务 逻 辑 ; (3) 处 理 客 户 已 更 改 的 业 务 目 标 ; (4) 符 合 组 织 对 敏 捷 或 迭 代 开 发 过 程 的 使 用 如 果 存 在 以 上 这 些 可 能 性, 尤 其 是 当 更 改 复 杂 if-else 逻 辑 的 开 发 人 员 并 不 是 以 前 编 写 代 码 的 开 发 人 员 时, 则 更 迫 切 需 要 一 个 无 需 太 多 复 杂 性 就 能 处 理 业 务 逻 辑 更 改 的 应 用 程 序 2. Drools 规 则 引 擎 Drools 是 Codehaus 的 一 个 开 源 项 目 最 近 被 纳 入 JBoss 门 下, 更 名 为 JBoss Rules, 成 为 了 JBoss 应 用 服 务 器 的 规 则 引 擎 [2] Drools 是 用 Java 语 言 编 写 的 开 放 源 码 规 则 引 擎, 基 于 Charles Forgy 的 RETE 算 法 的 规 则 引 擎 的 实 现 Drools 允 许 使 用 声 明 方 式 表 达 业 务 逻 辑 可 以 使 用 Java/XML 语 法 编 写 规 则, 这 对 于 入 门 Drools 十 分 有 用, 因 为 Java 代 码 可 以 直 接 嵌 入 规 则 文 件 中 Drools 还 具 有 如 下 一 些 优 点 : (1) 非 常 活 跃 的 社 区 ; (2) 易 用 ; (3) 快 速 的 执 行 速 度 ; (4) 在 Java 开 发 人 员 中 流 行 ; (5)JSR 94 [1] 兼 容 (JSR 94 是 Java Rule Engine API); (6) 免 费 3. 本 文 所 使 用 的 实 例 本 文 利 用 一 个 简 单 的 实 例 来 说 明 如 何 使 用 Drools 规 则 引 擎 来 实 现 业 务 逻 辑 - 1 -
下 列 假 设 为 应 用 程 序 解 决 的 虚 构 问 题 设 置 了 场 景 : (1) 某 人 的 年 龄 大 于 或 等 于 18 岁, 则 允 许 登 记 信 用 卡 ; (2) 某 人 的 年 龄 小 于 18 岁, 则 不 允 许 登 记 信 用 卡 3.1 不 利 用 规 则 引 擎 实 现 的 代 码 实 例 清 单 1. 使 用 if-else 语 句 实 现 业 务 规 则 逻 辑 String personname = person.getname(); int age = person.getage(); if (age >= 18) { System.out.println("credit allowed for " + personname); else { System.out.println("credit denied for " + personname); 清 单 1 中 的 代 码 只 是 一 个 实 例, 很 简 单, 不 是 太 复 杂 但 是 企 业 级 java 应 用 中 的 业 务 逻 辑 要 远 比 这 个 复 杂 得 多 如 果 要 对 这 些 复 杂 的 业 务 逻 辑 进 行 更 改, 需 要 十 分 小 心 一 堆 互 相 缠 绕 的 if-else 语 句 正 试 图 捕 获 已 经 为 应 用 程 序 标 识 的 业 务 逻 辑 如 果 您 对 业 务 规 则 不 甚 了 解, 就 无 法 一 眼 看 出 代 码 的 意 图 [4] 3.2 利 用 Drools 规 则 引 擎 实 现 的 代 码 实 例 (1) 规 则 规 则 是 对 商 业 知 识 的 编 码 一 条 规 则 有 attributes, 一 个 Left Hand Side(LHS) 和 一 个 Right Hand Side(RHS) rule "name" <attribute> <value> End <LHS> <RHS> 清 单 2. 规 则 的 一 般 形 式 业 务 规 则 的 理 论 基 础 是 : 设 置 一 个 或 多 个 条 件, 当 满 足 这 些 条 件 时 会 触 发 一 个 或 多 个 操 作 [3] 规 则 的 LHS 由 一 个 或 多 个 条 件 (Conditions) 组 成 当 所 有 的 条 件 (Conditions) 都 满 足 并 为 真 时,RHS 将 被 执 行 RHS 被 称 为 结 果 (Consequence) LHS 和 RHS 类 似 于 清 单 3 中 的 if 语 句 : if (<LHS>) { <RHS> 清 单 3. 与 规 则 等 价 的 if 语 句 (2) 本 文 中 所 用 实 例 的 规 则 文 件 - 2 -
rule "Credit Allowed" end person : Person( age >= 18 ) 清 单 4. 本 文 中 所 用 实 例 的 规 则 文 件 credit.drl( 截 取 ) System.out.println( "credit allowed for " + person.getname() ); rule "Credit Denied" end Person( personname : name, age < 18 ) System.out.println( "credit denied for " + personname ); (3) 构 建 核 心 代 码 drl 规 则 文 件 创 建 后, 它 们 被 读 入 一 个 解 析 器, 使 用 ANTLR 3 语 法 进 行 解 析 解 析 器 对 语 法 进 行 正 确 性 的 检 查, 然 后 产 生 一 种 中 间 结 构 descr,descr 用 AST 来 描 述 规 则 AST 然 后 被 传 到 PackageBuilder, 由 PackagBuilder 来 产 生 Packaged 对 象 PackageBuilder 还 承 担 着 一 些 代 码 产 生 和 编 译 的 工 作, 这 些 对 于 产 生 Package 对 象 都 时 必 需 的 RuleBase 是 一 个 运 行 时 组 件, 它 包 含 了 一 个 或 多 个 Package 对 象 可 以 在 任 何 时 刻 将 一 个 Package 对 象 加 入 或 移 出 RuleBase 对 象 一 个 RuleBase 对 象 可 以 在 任 意 时 刻 实 例 化 一 个 或 多 个 WorkingMemory 对 象, 在 它 的 内 部 保 持 对 这 些 WorkingMemory 的 弱 引 用 WorkingMemory 由 一 系 列 子 组 件 组 成 当 应 用 程 序 中 的 对 象 利 用 assertobject() 方 法 被 assert 进 WorkingMemory 后, 调 用 fireallrules() 方 法 来 执 行 规 则 清 单 5. 本 文 中 所 用 实 例 的 核 心 代 码 CreditExample.java( 截 取 ) // PackageBuilder 提 供 了 简 便 的 API, 利 用 addpackagefromdrl 方 法 // 从 传 入 的 Reader 实 例 产 生 descr AST 模 型 PackageBuilder builder = new PackageBuilder(); try { Reader arg0 = new InputStreamReader(CreditExample.class.getResourceAsStream("/credit.drl")); builder.addpackagefromdrl(arg0); catch (DroolsParserException e) { catch (IOException e) { // RuleBase 用 RuleBaseFactory 来 实 例 化, 默 认 返 回 一 个 ReteOO RuleBase // 可 以 传 入 参 数 来 指 定 采 用 ReteOO 或 Leaps // 然 后, 用 addpackage 方 法 加 入 Package 实 例 RuleBase rulebase = RuleBaseFactory.newRuleBase(); try { rulebase.addpackage(builder.getpackage()); - 3 -
catch (Exception e) { // rulebase 保 持 着 到 它 所 产 生 的 WorkingMemoryd 的 弱 引 用 WorkingMemory workingmemory = rulebase.newworkingmemory(); // 业 务 逻 辑 相 关 代 码 // // 调 用 fireallrules() 激 发 规 则 workingmemory.fireallrules(); 这 样, 原 本 需 要 写 在 程 序 中 的 业 务 逻 辑 便 抽 取 出 来, 形 成 一 个 规 则 文 件, 当 我 们 需 要 修 改 这 些 规 则 的 时 候 就 不 需 要 对 编 译 好 的 代 码 进 行 修 改, 而 只 是 修 改 一 下 规 则 文 件 中 的 具 体 规 则 即 可 同 时 也 就 省 去 了 重 新 编 译 和 部 署 的 成 本 另 一 方 面, 对 规 则 的 集 中 管 理 也 使 得 开 发 和 维 护 人 员 将 更 多 的 精 力 投 入 到 程 序 的 流 程 上, 而 业 务 规 则 也 可 以 由 熟 悉 业 务 逻 辑 的 规 则 管 理 人 员 来 进 行 集 中 开 发 和 维 护 上 从 而 大 大 提 高 了 应 用 的 开 发 效 率 和 维 护 成 本 4. 结 束 语 本 文 简 单 介 绍 了 基 于 规 则 开 发 应 用 系 统 的 一 些 主 要 概 念, 并 用 Java 和 Drools 开 发 了 一 个 基 于 规 则 引 擎 的 示 例 应 用 从 实 例 可 以 看 出 规 则 引 擎 技 术 为 管 理 多 变 的 业 务 逻 辑 提 供 了 一 种 解 决 方 案 规 则 引 擎 既 可 以 管 理 应 用 层 的 业 务 逻 辑 又 可 以 使 表 示 层 的 页 面 流 程 可 订 制 这 就 给 软 件 架 构 师 设 计 大 型 信 息 系 统 提 供 了 一 项 新 的 选 择 - 4 -
参 考 文 献 [1] 缴 明 洋 谭 庆 平. Java 规 则 引 擎 工 作 原 理 及 其 应 用. 计 算 机 与 信 息 技 术, 2006-04-06. [2] FORGYCL.Rete:a fast Algorithm for the many pattern/many object pattern match problem[j].artificial Intelligence,1982:17-37. [3] 李 国 乐. Java 规 则 引 擎 与 其 API. http://www-128.ibm.com/developerworks/cn/java/j-java-rules/. 2005-07-01 [4] Ricardo Olivieri. 使 用 Drools 规 则 引 擎 实 现 业 务 逻 辑. http://www-128.ibm.com/developerworks/cn/java/j-drools/. 2006-06-19 Application of Business Logic with Drools Rule Engine Liu Ji,Zhao Guangli Dalian Maritime University, Dalian Liaoning (116026) Abstract Nowadays, in enterprise Java application, business logics become more and more complicated, and these complex business logics are widespread distributed in the application. The costs both in the perspective of development and maintenance are very high, and very difficult. But rule engine, which centralized manage the business rules, can reduce the complexity of the realization of complex business logics, in mean while, reduce the costs of development and maintenance. This paper will show you how to use Drools to do this in an enterprise Java application. Keywords: Drools; Rule Engine; Business Logic 作 者 简 介 : 刘 际, 男, 大 连 海 事 大 学 计 算 机 学 院 硕 士 研 究 生, 在 Web 架 构 以 及 企 业 级 Java 应 用 方 面 有 较 丰 富 的 经 验 ; 赵 广 利, 男, 副 教 授, 大 连 海 事 大 学 计 算 机 学 院 硕 士 生 导 师, 主 要 从 事 网 络 方 向 的 研 究 - 5 -