activiti 5.21工作流规则引擎扩展(businessRuleTask)
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
背景介紹:
公司有自己的規(guī)則引擎配置平臺(tái),執(zhí)行核心為drools,配置后生成規(guī)則腳本,存入數(shù)據(jù)庫(kù),執(zhí)行的時(shí)候調(diào)用drools的Api,關(guān)鍵代碼:
?? ??? ?StatelessSession statelessSession = ruleBase.newStatelessSession();
?? ??? ?statelessSession.setGlobal("externalConditionResult", true);
? ? ? ? statelessSession.execute(list);
以前一直是在后臺(tái)硬編碼調(diào)用每一個(gè)規(guī)則。
使用activiti5工作流引擎,節(jié)點(diǎn)使用上只是用了用戶(hù)任務(wù)和自動(dòng)任務(wù),封裝在兩個(gè)方面:1.流程啟動(dòng),任務(wù)獲取,完成任務(wù),也就是對(duì)這幾個(gè)API的封裝,同時(shí)引入了流程業(yè)務(wù)關(guān)聯(lián)表。2。在流程節(jié)點(diǎn)分配這塊使用我們系統(tǒng)的崗位或者角色,擁有該崗位/角色的人都可以處理這個(gè)任務(wù),分配到崗位/角色這塊是通過(guò)規(guī)則配置的,后臺(tái)也是硬編碼的,現(xiàn)在平臺(tái)升級(jí)了以后,有這么個(gè)需求,就是流程編輯器上可以直接配置規(guī)則節(jié)點(diǎn),這樣的話(huà),用戶(hù)可以直接修改流程圖,選擇要調(diào)用的規(guī)則
activiti5本身是支持規(guī)則節(jié)點(diǎn)的,網(wǎng)上查一查,也能查到一些資料,總結(jié)一下:
<property name="customPostDeployers">
<list>
<bean class="org.activiti.engine.impl.rules.RulesDeployer" />
</list>
</property>
就是說(shuō)執(zhí)行到規(guī)則節(jié)點(diǎn)的時(shí)候,以.drl結(jié)尾的drool腳本會(huì)交給RulesDeploer部署,加載到內(nèi)存,供規(guī)則節(jié)點(diǎn)執(zhí)行器執(zhí)行。
4。在流程編輯器上的規(guī)則節(jié)點(diǎn)添加規(guī)則名,輸入變量,輸出變量,繼承JavaDelegate獲取輸出變量,或者直接在流程圖上根據(jù)流程變量zhi配置節(jié)點(diǎn)的走向
這樣看就完活了,但是實(shí)際執(zhí)行我們的規(guī)則的時(shí)候怎么調(diào)試到報(bào)錯(cuò),這方面沒(méi)有完善的文檔,只能看源碼了只能看源代碼了。
首先我們的規(guī)則執(zhí)行方式是無(wú)狀態(tài)的StatelessKnowledgeSession,結(jié)果變量就是一個(gè)實(shí)體類(lèi),是以在內(nèi)存中更新全局變量的方式返回的。
規(guī)則節(jié)點(diǎn)的執(zhí)行是BusinessRuleTaskActivityBehavior來(lái)處理的
?KnowledgeBase knowledgeBase =RulesHelper.findKnowledgeBaseByDeploymentId(deploymentId);?
?StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
1.通過(guò)流程實(shí)例部署ID,在內(nèi)存中找到以.drl結(jié)尾的腳本名稱(chēng),如果沒(méi)有,重新查詢(xún)act_ge_bytearray表,加載到內(nèi)存,添加到知識(shí)庫(kù).
2.獲取規(guī)則節(jié)點(diǎn)上配置的輸入輸出變量,規(guī)則名,如果不配置規(guī)則名,則全部執(zhí)行,執(zhí)行方式是通過(guò)有狀態(tài)StatefulKnowledgeSession的fireAllRules來(lái)執(zhí)行規(guī)則腳本,其中一個(gè)關(guān)鍵點(diǎn)是我們的規(guī)則腳本里面很多個(gè)規(guī)則名,總不能一個(gè)一個(gè)寫(xiě)到編輯器上面吧,重寫(xiě)執(zhí)行源碼,發(fā)現(xiàn)工作流實(shí)現(xiàn)了drools的規(guī)則匹配,只需修改我們的規(guī)則名已相同的名字結(jié)尾,流程編輯器上配置這個(gè)相同的名字,就可以全部執(zhí)行了,對(duì)于結(jié)果變量,drools不支持在他的工組內(nèi)存中更新全局變量,如果需要這樣做,就要調(diào)用ksession.setGlobal("ruleResultBase", obj);將全局變量set到他的工作內(nèi)存,獲取結(jié)果變量是一個(gè)集合,規(guī)則那一套基本不會(huì)改動(dòng),那怎么辦,直接修改改這個(gè)類(lèi)源碼好了,修改為獲取當(dāng)個(gè)實(shí)體(不是一個(gè)好方法,后面會(huì)說(shuō)到),就這樣把源碼拿出來(lái)改了,可以部署了,調(diào)試也通過(guò)了。。。。,
第一個(gè)問(wèn)題解決了:通過(guò)改動(dòng)BusinessRuleTaskActivityBehavior源碼,工作流可以調(diào)用我們的規(guī)則腳本,可以和規(guī)則聯(lián)動(dòng)了。
public void execute(ActivityExecution execution) throws Exception {PvmProcessDefinition processDefinition = execution.getActivity().getProcessDefinition();String deploymentId = processDefinition.getDeploymentId();KnowledgeBase knowledgeBase = RulesHelper.findKnowledgeBaseByDeploymentId(deploymentId); StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();if (variablesInputExpressions != null) {Iterator<Expression> itVariable = variablesInputExpressions.iterator();while (itVariable.hasNext()) {Expression variable = itVariable.next();Object obj=variable.getValue(execution);if(obj instanceof IRuleResultBase){//設(shè)置全局變量ksession.setGlobal("ruleResultBase", obj);}ksession.insert(variable.getValue(execution));}}if (!rulesExpressions.isEmpty()) {RulesAgendaFilter filter = new RulesAgendaFilter();Iterator<Expression> itRuleNames = rulesExpressions.iterator();while (itRuleNames.hasNext()) {Expression ruleName = itRuleNames.next();filter.addSuffic(ruleName.getValue(execution).toString());}filter.setAccept(!exclude);ksession.fireAllRules(filter);} else {ksession.fireAllRules();}//客戶(hù)化 結(jié)果bean/* Collection<Object> ruleOutputObjects = ksession.getObjects();if (ruleOutputObjects != null && !ruleOutputObjects.isEmpty()) {Collection<Object> outputVariables = new ArrayList<Object>();for (Object object : ruleOutputObjects) {outputVariables.add(object);}execution.setVariable(resultVariable, outputVariables);}*//*ruleResultBase=(RuleResultBase) ksession.getGlobal("ruleResultBase");Collection<Object> outputVariables = new ArrayList<Object>();outputVariables.add(ruleResultBase);execution.setVariable(resultVariable, ruleResultBase);*/execution.setVariable(resultVariable, ksession.getGlobal("ruleResultBase"));ksession.dispose();leave(execution);}?
但是有幾個(gè)問(wèn)題,規(guī)則編輯之后難道要重新部署流程嗎?看流程是如何加載規(guī)則的
public class RulesHelper {public static KnowledgeBase findKnowledgeBaseByDeploymentId(String deploymentId) {DeploymentCache<Object> knowledgeBaseCache = Context.getProcessEngineConfiguration().getDeploymentManager().getKnowledgeBaseCache();KnowledgeBase knowledgeBase = (KnowledgeBase) knowledgeBaseCache.get(deploymentId);if (knowledgeBase==null) {DeploymentEntity deployment = Context.getCommandContext().getDeploymentEntityManager().findDeploymentById(deploymentId);if (deployment==null) {throw new ActivitiObjectNotFoundException("no deployment with id "+deploymentId, Deployment.class);}Context.getProcessEngineConfiguration().getDeploymentManager().deploy(deployment);knowledgeBase = (KnowledgeBase) knowledgeBaseCache.get(deploymentId);if (knowledgeBase==null) {throw new ActivitiException("deployment "+deploymentId+" doesn't contain any rules");}}return knowledgeBase;} }發(fā)現(xiàn)上面代碼從緩存中取KnowledgeBase,?if (knowledgeBase==null),那么根據(jù)部署id,去數(shù)據(jù)庫(kù)查詢(xún),然后交給Deployer來(lái)部署,這是一個(gè)接口:
public interface Deployer {void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings); }對(duì)于規(guī)則的部署,activiti的實(shí)現(xiàn)類(lèi)為前面提到的,配置文件中配置的RulesDeployer
public class RulesDeployer implements Deployer {private static final Logger log = LoggerFactory.getLogger(RulesDeployer.class);public void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings) {log.debug("Processing deployment {}", deployment.getName());KnowledgeBuilder knowledgeBuilder = null;DeploymentManager deploymentManager = Context.getProcessEngineConfiguration().getDeploymentManager();Map<String, ResourceEntity> resources = deployment.getResources();for (String resourceName : resources.keySet()) {log.info("Processing resource {}", resourceName);if (resourceName.endsWith(".drl")) { // is only parsing .drls sufficient? what about other rule dsl's? (@see ResourceType)if (knowledgeBuilder==null) {knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();}ResourceEntity resourceEntity = resources.get(resourceName);byte[] resourceBytes = resourceEntity.getBytes();Resource droolsResource = ResourceFactory.newByteArrayResource(resourceBytes);knowledgeBuilder.add(droolsResource, ResourceType.DRL);}}if (knowledgeBuilder!=null) {KnowledgeBase knowledgeBase = knowledgeBuilder.newKnowledgeBase();deploymentManager.getKnowledgeBaseCache().add(deployment.getId(), knowledgeBase);}} }從這里可以知道,文件必須是以.drl結(jié)尾,所謂部署就是將規(guī)則腳本添加到知識(shí)庫(kù),用部署ID,作為key,KnowledgeBase作為value,加載到本地緩存,那么解決辦法如下:
- 重新部署流程,帶著更新后的規(guī)則腳本
- 直接修改此類(lèi),設(shè)置一個(gè)監(jiān)聽(tīng)器,時(shí)時(shí)更新緩存
- 這個(gè)類(lèi)是實(shí)現(xiàn)的Deployer接口,并且在配置文件中可配置的,那么最好的辦法就是,實(shí)現(xiàn)我們自己的類(lèi)來(lái)擴(kuò)展
轉(zhuǎn)載于:https://my.oschina.net/u/2886096/blog/1819094
總結(jié)
以上是生活随笔為你收集整理的activiti 5.21工作流规则引擎扩展(businessRuleTask)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 阿里云有一群 “猪猪侠”
- 下一篇: 图片和图形之性能和视图层次结构(18)