規則引擎drools封裝


一.前言

    網上規則引擎drools介紹很多,並且有很多細致的說明,作者也不敢托大說自己的好用,但作者經過2個項目使用過規則引擎后,自己對規則引擎的理解並進行封裝,對規則內容及如何使用,有自己的一番實踐,並提供源代碼,供大家參考


二.設計思路及具體代碼

    首先我希望是輕量級的使用drools,不希望使用太過復雜的架構,以這種思路入手,就可以與任何項目輕易融入,這樣就需要能夠將drools規則的來源,從規則文件(drl)中可以從maven和自己的數據庫中獲取,腳本是動態的,配合drools6.5支持通過maven接入的規則的API,就可以做到從任何處獲取規則內容

一個工具類DroolsUtils


   
   
  
  
          
  1. package com.vip.jie.rule.util;
  2. import org.drools.compiler.kie.builder.impl.InternalKieModule;
  3. import org.kie.api.KieServices;
  4. import org.kie.api.builder.KieBuilder;
  5. import org.kie.api.builder.KieFileSystem;
  6. import org.kie.api.builder.ReleaseId;
  7. import org.kie.api.builder.model.KieBaseModel;
  8. import org.kie.api.builder.model.KieModuleModel;
  9. import org.kie.api.builder.model.KieSessionModel;
  10. import org.kie.api.conf.EqualityBehaviorOption;
  11. import org.kie.api.conf.EventProcessingOption;
  12. import java.io.IOException;
  13. /**
  14. * 動態生成kjar
  15. * @author jie01.zhu
  16. * @DateTime 2018/3/19 22:14
  17. */
  18. public class DroolsUtils {
  19. /**
  20. * 創建默認的kbase和stateful的kiesession
  21. *
  22. * @param ks
  23. * @param isdefault
  24. * @return
  25. */
  26. private static KieFileSystem createKieFileSystemWithKProject(KieServices ks, boolean isdefault) {
  27. KieModuleModel kproj = ks.newKieModuleModel();
  28. KieBaseModel kieBaseModel1 = kproj.newKieBaseModel( "KBase").setDefault(isdefault)
  29. .setEqualsBehavior(EqualityBehaviorOption.EQUALITY)
  30. .setEventProcessingMode(EventProcessingOption.STREAM);
  31. // Configure the KieSession.
  32. kieBaseModel1.newKieSessionModel( "KSession").setDefault(isdefault)
  33. .setType(KieSessionModel.KieSessionType.STATEFUL);
  34. KieFileSystem kfs = ks.newKieFileSystem();
  35. kfs.writeKModuleXML(kproj.toXML());
  36. return kfs;
  37. }
  38. /**
  39. * 創建kjar的pom
  40. *
  41. * @param releaseId
  42. * @param dependencies
  43. * @return
  44. */
  45. private static String getPom(ReleaseId releaseId, ReleaseId... dependencies) {
  46. String pom = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  47. + "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
  48. + " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"
  49. + " <modelVersion>4.0.0</modelVersion>\n" + "\n" + " <groupId>" + releaseId.getGroupId()
  50. + "</groupId>\n" + " <artifactId>" + releaseId.getArtifactId() + "</artifactId>\n" + " <version>"
  51. + releaseId.getVersion() + "</version>\n" + "\n";
  52. if (dependencies != null && dependencies.length > 0) {
  53. pom += "<dependencies>\n";
  54. for (ReleaseId dep : dependencies) {
  55. pom += "<dependency>\n";
  56. pom += " <groupId>" + dep.getGroupId() + "</groupId>\n";
  57. pom += " <artifactId>" + dep.getArtifactId() + "</artifactId>\n";
  58. pom += " <version>" + dep.getVersion() + "</version>\n";
  59. pom += "</dependency>\n";
  60. }
  61. pom += "</dependencies>\n";
  62. }
  63. pom += "</project>";
  64. return pom;
  65. }
  66. /**
  67. * 初始化一個kjar:把原有的drl包含進新建的kjar中
  68. *
  69. * @param ks
  70. * @param releaseId
  71. * @return
  72. * @throws IOException
  73. */
  74. public static InternalKieModule initKieJar(KieServices ks, ReleaseId releaseId) throws IOException {
  75. KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);
  76. kfs.writePomXML(getPom(releaseId));
  77. KieBuilder kieBuilder = ks.newKieBuilder(kfs);
  78. if (!kieBuilder.buildAll().getResults().getMessages().isEmpty()) {
  79. throw new IllegalStateException( "Error creating KieBuilder.");
  80. }
  81. return (InternalKieModule) kieBuilder.getKieModule();
  82. }
  83. public static InternalKieModule createKieJar(KieServices ks, ReleaseId releaseId, DroolsResource droolsResource) {
  84. KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);
  85. kfs.writePomXML(getPom(releaseId));
  86. kfs.write( "src/main/resources/" + droolsResource.getTargetResourceName(), droolsResource.getResource());
  87. KieBuilder kieBuilder = ks.newKieBuilder(kfs);
  88. if (!kieBuilder.getResults().getMessages().isEmpty()) {
  89. throw new IllegalStateException(
  90. "Error creating KieBuilder. errorMsg:" + kieBuilder.getResults().getMessages());
  91. }
  92. return (InternalKieModule) kieBuilder.getKieModule();
  93. }
  94. }

重點調用參考:


   
   
  
  
          
  1. String fileName = "jie-" + group + "-rules";
  2. /**
  3.  * 指定kjar包
  4.  */
  5. final ReleaseId releaseId = kieServices.newReleaseId( "com.vip.jie", fileName, "1.0.0");
  6. log.info( "DroolsGetKieSession fileName:{}", fileName);
  7. log.info( "[DroolsGetKieSession] drlStr:{}", drlStr);
  8. // 創建初始化的kjar
  9. InternalKieModule kJar = DroolsUtils.createKieJar(kieServices, releaseId,
  10. new DroolsResource(ResourceFactory.newByteArrayResource(drlStr.getBytes()),
  11. fileName + ".drl"));

    其次再將如何讓使用者可以很靈活的接入,利用可變參數類型,將入參對象無限制傳入,由規則腳本去決定入參的變化,通過此種方式可以比較好的實現業務靈活接入

如下單元測試類:


   
   
  
  
          
  1. package com.vip.jie.rule.service.impl;
  2. import com.vip.jie.rule.object.User;
  3. import com.vip.jie.rule.service.RuleManager;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.junit.Test;
  6. import static junit.framework.TestCase.fail;
  7. /**
  8. * 規則測試
  9. * @author jie01.zhu
  10. * @DateTime 2018/3/19 21:17
  11. *
  12. */
  13. @Slf4j
  14. public class RuleManagerImplTest {
  15. private RuleManager ruleManager = new RuleManagerImpl();
  16. private String getRuleContent() {
  17. StringBuilder stringBuilder = new StringBuilder();
  18. stringBuilder.append( "import com.vip.jie.rule.object.User;\n");
  19. stringBuilder.append( "rule test1 when\n");
  20. stringBuilder.append( "user : User(age==20)\n");
  21. stringBuilder.append( "then\n");
  22. stringBuilder.append( "user.setName(\"張三\");\n");
  23. stringBuilder.append( "end\n");
  24. return stringBuilder.toString();
  25. }
  26. @Test
  27. public void executeRule1() throws Exception {
  28. User user = new User();
  29. user.setAge( 20);
  30. //調用規則
  31. ruleManager.executeRule( "test1", getRuleContent(), user);
  32. log.info( "test result:{}", user.toString());
  33. if (! "張三".equals(user.getName())) {
  34. fail( "error rule");
  35. }
  36. }
  37. @Test
  38. public void executeRule2() throws Exception {
  39. User user = new User();
  40. user.setAge( 21);
  41. //調用規則
  42. ruleManager.executeRule( "test1", getRuleContent(), user);
  43. log.info( "test result:{}", user.toString());
  44. if ( "張三".equals(user.getName())) {
  45. fail( "error rule");
  46. }
  47. }
  48. }

三.對應示例源代碼獲取方式

githup:

https://github.com/jie01/drools-demo

csdn資源下載地址:

https://download.csdn.net/download/vipshop_fin_dev/10296393


還有一些關於安全性及與spring的封裝思路,作者表示還會繼續完善,並還不是最終版本,有需要可以持續關注-_-!


與當前文章有關聯的鏈接

業務框架之個性化監控方案



vipshop_ebs/朱傑

2018-03-19


原文地址:https://blog.csdn.net/vipshop_fin_dev/article/details/79618067


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM