`
welody
  • 浏览: 21216 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

(转)基于spring的应用增加简单的规则引擎

阅读更多
    任何大一点的软件项目都包含了许多叫做业务逻辑的东西。业务逻辑的准确描述还是有争议的。在为典型应用软件的生成的大量代码中,到处都是为如订单处理、武器控制系统、图形绘制等功能工作的零碎代码。这些代码与其他如处理持久化、日志、事务、语言偏好、框架特性及其他现代企业级应用有明显不同。

  业务逻辑通常与其他代码块紧密的混和在一起。当重量级的侵入式框架(如EJB)被使用时,区别业务逻辑与框架生成的代码就变得非常困难。

  有一个软件需求在需求定义文档很难准确描述,却拥有使软件项目成功或失败的能力:适应性,这是用来衡量软件响应业务变更容易程度的标准。

  现代企业要求响应快速及灵活,他们对企业软件也有同样的要求。可能你今天辛苦实现的业务规则在明天就被废弃了而且要求你根据变更快速而准确的改变。当你的包含业务逻辑的代码隐藏在大量其他代码中时,修改就变得缓慢、痛若且易出错了。

  在今天的企业级软件中没有奇迹,比较流行的是规则引擎和各种业务过程管理(BPM)系统。如果你看一下市场上的宣传,这类工具都承诺一件事:保存在仓库中的捕获业务逻辑的圣杯能够清晰的分离且由自己维护,并随时准备让你现有的应用来调用。

  虽然商业的规则引擎和BPM系统有许多优点,但也有不少缺点。最大的缺点就是价格,通常很容易就达到7位数。另一个就是除了主要的行业规范和众多记在纸上的标准外缺乏事实上的标准。而且随着越来越多的软件项目采用敏捷、轻量级的快速开发方法,这些重量级的工具变得不符合潮流了。

  在这篇文章中,我们建立了一个简单的规则引擎,一方面平衡系统与业务逻辑的分离,另一方面由于他基于目前流行的强大的J2EE框架因而不需要承受商业软件的复杂性与不协调性。

  J2EE世界中的Spring时代

  在企业级软件的复杂性变得不能忍受及业务逻辑问题越来越重要时,Spring及类似的框架产生了。可以断定Spring在以后很长一段时间内是企业级Java中的佼佼者。Spring提供了很多工具及少量代码约定使J2EE的开发更面向对象,更容易也更有趣。

  Spring的核心是IoC原则,这是一个奇特而超负荷的名字,但包含下面的简单想法:

  ●功能代码需要分开到更小的可管理片断
  ●这些片断是简单的,标准的JavaBean(简单的Java类拥有但不包含全部的JavaBean规范)
  ●你不需要参与管理这些Bean(如创建、销毁、设置依赖)
  ●相反Spring容器通过上下文定义来为你做这些(通常为XML文件格式)

  Spring也提供了很多其他特性,如完整而强大的MVC框架,简便的JDBC开发包装及其他框架。但那些主题已经超出这篇幅文章的讨论范围。

  在我描述需要什么来创建基于SPRING应用的简单规则引擎之前,让我们想一下为什么这是一种好的想法。

  规则引擎设计有两点有趣的特性使其更有价值:

  ●首先,从应用领域分离了业务逻辑代码。
  ●其次,可配置性意味着业务规则的定义及其使用的顺序被存储在应用的外部,这样就可以由规则创建人员来控制而不是应用的使用者或者开发人员了。

  Spring为规则引擎提供了一个好的方法。一个良好编码的Spring应用的强组件化的设计会使你的代码变成更小的、可管理的分散片断,这样就更易在Spring的上下文定义中配置。

  继续了解在规则引擎设计的需求与Spring设计提供的功能之间的结合点。

  基于Spring的规则引擎的设计

  我们在Spring控制的JavaBean基础上开始设计,这里我们叫做规则引擎组件。我们来定义下面两种我们可能需要的组件类型:

  ●操作—在应用逻辑中确定用来做什么的组件
  ●规则—在一系列行为的逻辑流中做出决定的组件

  我们都是面向对象设计的追随者,下面的基类建立了所有我们的组件需要通过参数被其他组件调用的基本功能:
public abstract class AbstractComponent {
  public abstract void execute(Object arg) throws Exception;
  }

    当然基类是抽象的因为我们根本不需要这样的实例。
    AbstractAction的代码扩展了基类来实现其他具体的操作:
public abstract class AbstractAction extends AbstractComponent {
   private AbstractComponent nextStep;
      public void execute(Object arg) throws Exception {
      this.doExecute(arg);
      if(nextStep != null)
         nextStep.execute(arg);
   }
   protected abstract void doExecute(Object arg) throws Exception;
   public void setNextStep(AbstractComponent nextStep) {
      this.nextStep = nextStep;
   }
   public AbstractComponent getNextStep() {
      return nextStep;
   }
}

    你可以看到,AbstractAction做两件事:首先他保存在规则引擎中被激活的下一个组件的定义;其次在他的execute()方法中,调用被具体类实现的doExecute()方法,在doExecute()返回后,如果存在下一个组件则调用他。

  我们的AbstractRule也相当简单:
public abstract class AbstractRule extends AbstractComponent {
   private AbstractComponent positiveOutcomeStep;
   private AbstractComponent negativeOutcomeStep;
      public void execute(Object arg) throws Exception {
      boolean outcome = makeDecision(arg);
      if(outcome)
         positiveOutcomeStep.execute(arg);
      else
         negativeOutcomeStep.execute(arg);
   }
   protected abstract boolean makeDecision(Object arg) throws Exception;
//为简单起见,positiveOutcomeStep和negativeOutcomeStep的Getters和setters均已省略

    在其execute()方法中,AbstractAction调用由子类实现的makeDecision()方法,然后根据方法的返回值,调用组件定义的肯定或否定结果的方法。

  在我们介绍了SpringRuleEngine类后我们的设计就基本完成了:
public class SpringRuleEngine {
      private AbstractComponent firstStep;
      public void setFirstStep(AbstractComponent firstStep) {
      this.firstStep = firstStep;
   }
      public void processRequest(Object arg) throws Exception {
      firstStep.execute(arg);
   }
   }

这就是我们规则引擎主类的全部:定义第一个业务逻辑中的组件及开始执行的方法。

  但是请稍等,在哪里绑定我们的类使之可以工作呢?下面你就可以看到如何利用Spring来帮助我们完成工作的方法了。
   
    在操作中的基于Spring的规则引擎

  让我们看一下这个框架如何工作的具体实例吧。想象下面的用例:我们需要开发负责贷款申请的应用程序。我们需要满足下面的条件:

  ●检查应用的完整性否则驳回
  ●检查应用是否来自我们授权处理业务的应用。
  ●检查申请者的月收支比是否满足我们的要求。
  ●输入的申请通过我们不知道实现细节的持久服务被存储在数据库中,我们只知道他的接口(可能这个开发被外包到印度了)
  ●业务规则是可以改变的,这也是为什么需要规则引擎的设计了。

  首先,设计一个表示贷款申请的类:
public class LoanApplication {
  
   public static final String INVALID_STATE = "Sorry we are not doing business in your state";
   public static final String INVALID_INCOME_EXPENSE_RATIO = "Sorry we cannot provide the loan given this expense/income ratio";
   public static final String APPROVED = "Your application has been approved";
   public static final String INSUFFICIENT_DATA = "You did not provide enough information on your application";
   public static final String INPROGRESS = "in progress";
  
   public static final String[] STATUSES =
      new String[] {
         INSUFFICIENT_DATA, INVALID_INCOME_EXPENSE_RATIO, INVALID_STATE, APPROVED, INPROGRESS
      };

   private String firstName;
   private String lastName;
   private double income;
   private double expences;
   private String stateCode;
   private String status;
  
   public void setStatus(String status) {
      if(!Arrays.asList(STATUSES).contains(status))
         throw new IllegalArgumentException("invalid status:" + status);
      this.status = status;
   }

// 其他getters and setters已被省略

}

我们使用的持久服务拥有如下接口:
public interface LoanApplicationPersistenceInterface {
   public void recordApproval(LoanApplication application) throws Exception;
   public void recordRejection(LoanApplication application) throws Exception;
   public void recordIncomplete(LoanApplication application) throws Exception;
}

我们迅速开发一个什么也不做只是用来满足接口约定的MockLoanApplicationPersistence类来欺骗接口。

  我们使用下面的SpringRuleEngine类的子类来加载Spring上下文并开始处理:
public class LoanProcessRuleEngine extends SpringRuleEngine {
   public static final SpringRuleEngine getEngine(String name) {
      ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("SpringRuleEngineContext.xml");
      return (SpringRuleEngine) context.getBean(name);
   }
}

这时候,我们已经有了代码框架了,因此是时候写JUnit测试了,代码如下。其中包含一些假设:我们期望公司仅在两种州运作,德克萨斯和密歇根。而且我们只接受收支比在70%或更好的人的贷款申请。
public class SpringRuleEngineTest extends TestCase {

   public void testSuccessfulFlow() throws Exception {
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      application.setFirstName("John");
      application.setLastName("Doe");
      application.setStateCode("TX");
      application.setExpences(4500);
      application.setIncome(7000);
      engine.processRequest(application);
      assertEquals(LoanApplication.APPROVED, application.getStatus());
   }
  
   public void testInvalidState() throws Exception {
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      application.setFirstName("John");
      application.setLastName("Doe");
      application.setStateCode("OK");
      application.setExpences(4500);
      application.setIncome(7000);
      engine.processRequest(application);
      assertEquals(LoanApplication.INVALID_STATE, application.getStatus());
   }
  
   public void testInvalidRatio() throws Exception {
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      application.setFirstName("John");
      application.setLastName("Doe");
      application.setStateCode("MI");
      application.setIncome(7000);
      application.setExpences(0.80 * 7000); //too high     
      engine.processRequest(application);
      assertEquals(LoanApplication.INVALID_INCOME_EXPENSE_RATIO, application.getStatus());
   }
  
   public void testIncompleteApplication() throws Exception {     
      SpringRuleEngine engine = LoanProcessRuleEngine.getEngine("SharkysExpressLoansApplicationProcessor");
      LoanApplication application = new LoanApplication();
      engine.processRequest(application);
      assertEquals(LoanApplication.INSUFFICIENT_DATA, application.getStatus());
   }

显然单元测试会失败因为我们还没有实现任何的逻辑。然而,随着项目的进展,越来越多的测试通过,最后JUnit测试就全部通过了。

  让我们继续操作和规则的实现。我们希望操作与持久服务交互因此我们需要一个通用基类:
public abstract class AbstractPersistenceAwareAction extends AbstractAction {
   private LoanApplicationPersistenceInterface persistenceService;
   public void setPersistenceService(LoanApplicationPersistenceInterface persistenceService) {
      this.persistenceService = persistenceService;
   }
   public LoanApplicationPersistenceInterface getPersistenceService() {
      return persistenceService;
   }
}

在我们的进程中第一个请求贷款申请的业务规则已经完成:
public class ValidApplicationRule extends AbstractRule {
   protected boolean makeDecision(Object arg) throws Exception {
      LoanApplication application = (LoanApplication) arg;
      if(application.getExpences() == 0 ||
            application.getFirstName() == null ||
            application.getIncome() == 0 ||
            application.getLastName() == null ||
            application.getStateCode() == null) {
         application.setStatus(LoanApplication.INSUFFICIENT_DATA);
         return false;
      }
      return true;
   }
}

    注意这个类的一些有趣的现象:他是完全自包含的。他可以由自己实例化或者任何外部的应用容器,而类中的逻辑可以独立的开发和测试。这些现象使类成为基于规则应用的完美的程序块。现在是时候通过Spring容器来绑定对象了。就象你在单元测试中看到的一样,我们使用LoanProcessRuleEngine类作为入口指向请求名为SharkysExpressLoansApplicationProcessor的Bean的规则引擎。下面是这个Bean如何在 SpringRuleEngineContext.xml定义:
   <!-- 规则引擎处理器 -->
   <bean id="SharkysExpressLoansApplicationProcessor" class="SpringRuleEngine">
      <property name="firstStep">
         <ref bean="ValidApplicationRule"/>
      </property>
   </bean>
这个Bean简单地指明ValidApplicationRule为业务处理的第一个步骤。这个组件如下定义:
   <!-- validation -->
   <bean id="ValidApplicationRule" class="ValidApplicationRule">
      <property name="positiveOutcomeStep">
         <ref bean="ValidStateRule"/>
      </property>
      <property name="negativeOutcomeStep">
         <ref bean="RejectionAction"></ref>
      </property>
   </bean>

你可以看到,规则自身也在Spring上下文中定义:如果贷款申请是合法的,应用会检查是否正确的州;否则控制传递给RejectionAction。

  RejectionAction也很简单:
public class ProcessRejectionAction extends AbstractPersistenceAwareAction {
   protected void doExecute(Object arg) throws Exception {
      LoanApplication application = (LoanApplication) arg;
      if(LoanApplication.INSUFFICIENT_DATA.equals(application.getStatus()))
         this.getPersistenceService().recordIncomplete(application);
      else
         this.getPersistenceService().recordRejection(application);
   }
}

它在Spring上下文中如下定义(注意引用了被伪类欺骗的持久服务):
   <!-- rejection -->
   <bean id="RejectionAction" class="ProcessRejectionAction">
      <property name="persistenceService">
         <ref bean="LoanApplicationPersistenceService"/>
      </property>

   </bean>
   <!-- persistence service -->
   <bean id="LoanApplicationPersistenceService" class="MockLoanApplicationPersistence"/>

我们的下一个业务规则检查是否贷款申请来自合法的州:
public class ValidStateRule extends AbstractRule {

   private List validStates;
  
   protected boolean makeDecision(Object arg) throws Exception {
      LoanApplication application = (LoanApplication) arg;
      if(validStates.contains(application.getStateCode())) {
         return true;
      }
      application.setStatus(LoanApplication.INVALID_STATE);
      return false;
   }

   public void setValidStates(List validStates) {
      this.validStates = validStates;
   }
} 

有趣的是,我们的代码并不知道哪些州是合法的。这些业务信息由上下文来定义:
<!-- check valid state -->

   <bean id="ValidStateRule" class="ValidStateRule">
      <property name="validStates">
         <list>
            <value>TX</value>
            <value>MI</value>
         </list>
      </property>
      <property name="positiveOutcomeStep">
         <ref bean="ValidIncomeExpenseRatioRule"/>
      </property>
      <property name="negativeOutcomeStep">
         <ref bean="RejectionAction"></ref>
      </property>
   </bean>

Spring的内建功能再一次让我们从代码中抽取出逻辑流程和参数数据,仅在外部配置就可以了。

  如你所见,Spring应用容器为我们的类提供了所有必须的绑定。在启动时,Spring创建所有必须的对象并设置相关的依赖。在运行时,我们的业务规则通过定义在Spring上下文而不是代码中的逻辑和参数数据来执行。

  贷款申请示例的其他部分可以用相同方法来配置和开发。完整的源程序及对应的Spring配置可以在资源中找到。

  总结

  在这篇文章中,我演示了通过Spring帮助你开发基于规则应用的众多方法中的一部分。你也可以使用其内置的AOP来支持在你的规则和操作中混合日志及事务代码而不会污染你先前的业务逻辑。

  SPRING应用上下文是可以重新加载的。应用可以修改业务规则和参数(通过修改XML文件)并在运行中重新加载上下文。想象这么做的GUI应用。这么做可以提供与价格为数百万的商业的规则引擎系统的类似功能。

  很期望这篇文章可以帮助你尝试一些新鲜而以令人振奋的方法来使你的代码在将来更加有效。
分享到:
评论

相关推荐

    基于Spring的规则引擎

    ### 基于Spring的规则引擎 #### 一、引言 随着信息技术的发展,企业级应用系统的复杂性不断增加,为了更好地应对不断变化的市场需求和业务环境,开发灵活、可扩展的应用系统成为当前的一个重要趋势。业务规则作为...

    基于Spring的业务规则引擎

    ### 基于Spring的业务规则引擎 #### 概述 业务规则引擎(Business Rule Engine, BRI)是一种专门用于处理复杂业务逻辑的技术方案。它能够帮助开发人员将业务规则从业务逻辑中抽离出来,形成独立的组件,从而简化...

    基于Spring 的业务规则引擎

    ### 基于Spring的业务规则引擎关键技术点 #### 1. 业务规则引擎的重要性及背景 业务规则引擎(Business Rule Engine, BPE)是一种重要的技术工具,它可以帮助企业快速应对市场变化,调整业务策略而无需修改核心...

    基于Spring + Drools6.4规则引擎代码实例.

    ### 基于Spring + Drools 6.4规则引擎代码实例详解 #### 知识点一:Drools规则引擎介绍与应用背景 Drools是一款强大的业务规则管理系统(BRMS),它提供了核心的业务规则引擎(BRE)、Web作者和规则管理应用程序...

    用Spring boot与Drools规则引擎写的Demo

    Spring Boot 是一个流行的Java开发框架,它简化了创建独立、生产级别的基于Spring的应用程序的流程。Drools,则是JBOSS公司推出的一款强大的规则引擎,用于处理业务规则和决策。这个“用Spring Boot与Drools规则引擎...

    基于Java的规则引擎

    - **Redhat JBoss Drools**:开源规则引擎,基于Maven构建,与Java EE和Spring框架集成良好,提供Drools Workbench进行规则管理。 - **JESS**:基于Lisp的规则引擎,主要用于教育和研究,因其简洁的语法和解释器而...

    规则引擎drools与spring整合

    Drools 是一个开源的、基于Java的业务规则管理系统(BRMS),它提供了一个规则引擎,用于在应用程序中执行业务规则。Spring 框架是Java开发中最常用的应用框架,它简化了依赖注入、事务管理等任务。将 Drools 与 ...

    Spring Boot+Drools规则引擎整合详解

    本文通过知识点的罗列,从Drools规则引擎的基本概念讲起,逐步深入到Spring Boot项目中整合Drools的具体步骤,再到如何使用决策表编辑器管理和编辑规则,最后展现了Drools在业务逻辑决策中的实际应用。通过以上内容...

    基于规则引擎的消息中心模块的设计与实现

    ### 基于规则引擎的消息中心模块的设计与实现 #### 一、背景介绍与问题定义 随着信息技术的发展,物流行业面临着越来越复杂的业务处理需求。为了提高物流系统的灵活性和可扩展性,采用Web服务(Web Services)、...

    基于SPRING框架的分布式工作流引擎的设计方法探索.pdf

    在分布式工作流引擎的设计与实现过程中,利用Spring框架已经成为业界的一个重要趋势,而本篇文章则深入探讨了基于Spring框架的分布式工作流引擎的设计方法。 Spring框架是当前流行的开源轻量级J2EE容器,它为应用...

    商用、开源规则引擎资料汇总

    - **Drools**:基于Rete算法的改进版本Rete-II,Drools是一款功能强大的开源规则引擎。它支持多种编程语言,并且与Spring框架紧密结合,便于集成到现有的Java应用中。 - **Mandarax**:采用反向推理技术,特别适合...

    规则引擎Drools在J2EE项目开发中的应用

    在J2EE项目开发中,规则引擎Drools扮演着重要的角色,它是一个开源的业务规则管理系统(BRMS),能够帮助开发者将业务规则从应用程序逻辑中分离出来,从而实现更灵活、可维护的代码结构。Drools的核心功能是解析、...

    规则引擎内部交流.7z

    7. 与Java的关系:由于标签为“java”,我们可以推测文档可能重点介绍了如何在Java环境中集成和使用规则引擎,例如使用Java API调用规则引擎服务,或者使用Spring框架来管理和配置规则引擎。 通过这两个文件的学习...

    Spring Boot与LiteFlow:轻量级流程引擎的集成与应用

    LiteFlow作为一款轻量级流程引擎,凭借其简单易用、高度可扩展性及高性能等特点,在Spring Boot等微服务架构中得到广泛应用。本文旨在详细介绍如何在Spring Boot项目中集成LiteFlow,并通过实例演示其工作原理和使用...

    规则引擎应用实践

    《规则引擎应用实践》 规则引擎是一种软件系统,它允许业务规则在运行时动态地更改,而无需修改程序代码。这种技术在IT行业中被广泛应用于决策支持系统、工作流管理和复杂事件处理等领域。本文将围绕Drools这一流行...

    基于Spring Boot的水电管理系统.zip

    基于Spring Boot的水电管理系统 项目概述 本项目是一个基于Spring Boot框架开发的水电管理系统,旨在提供高效、便捷的水电费用管理功能。系统集成了用户管理、费用查询、系统设置等多种功能,通过Spring Boot的...

    Drools-规则引擎

    Drools 提供了一个规则引擎,使得业务规则可以与应用程序的主体逻辑分离,从而更容易管理和调整。下面我们将深入探讨Drools 的核心概念和功能。 1. **核心概念** - **规则(Rule)**:规则是Drools 的基本单元,它...

    从Drools规则引擎到风控反洗钱系统V0.2.3

    然后,在Spring Boot应用中配置规则引擎。 ```java @Configuration public class KieConfig { @Bean public KieBase kieBase() { KieServices kieServices = KieServices.Factory.get(); KieFileSystem kfs = ...

    Drools5规则引擎开发教程.pdf

    《Drools5规则引擎开发教程》是一本深入解析Drools5这一强大规则引擎的指导书籍。Drools5是JBOSS公司推出的一款开源业务规则管理系统(BRMS),它基于Java语言,旨在帮助开发者将业务逻辑从应用程序中分离出来,实现...

    规则引擎-Java调用规则

    规则引擎在现代软件系统中扮演着重要角色,它允许业务逻辑与核心应用程序代码分离,使得规则可以在不修改源代码的情况下进行调整和更新。本篇主要介绍如何在Java环境中调用规则引擎,具体包括三种方法:Java类直接...

Global site tag (gtag.js) - Google Analytics