優雅的實現Activiti動態調整流程(自由跳轉、前進、後退、分裂、前加簽、後加簽等),含範例代碼!

來源:互聯網
上載者:User

標籤:

最近對Activiti做了一些深入的研究,對Activiti的流程機制有了些理解,對動態調整流程也有了一些實踐方法。

現在好好總結一下,一來是對這段時間自己辛苦探索的一個記錄,二來也是為後來者指指路~~~

如下內容準備採用QA的方式寫,很多問題都是當初自己極疑惑的問題,希望能為大家解惑!

Q:可以動態調整流程嗎?

A:可以!可以動態更改流程指向,或者建立新的節點,等等。。。

Q: 更改流程還需要注意什嗎?

A: 必須要實現持久化!否則一旦應用重啟,你的流程就犯糊塗了!譬如,你建立了一個新節點,但由於沒有持久化,重啟之後流程引擎找不到那個新節點了。。。

Q: 如何做到優雅?

A: 除了持久化之外,還記住盡量不要因為臨時調整直接更改現有活動(沒準這個活動後面還要照常使用呢!),這種情況可以考慮複製。第三,不要直接操作資料庫,或者SqlSession,記住自己寫Command!參見我前面的另外一篇文章。如下代碼示出執行某個activity後續流程的Cmd:

public class CreateAndTakeTransitionCmd implements Command<java.lang.Void>{private ActivityImpl _activity;private String _executionId;public CreateAndTakeTransitionCmd(String executionId, ActivityImpl activity){_executionId = executionId;_activity = activity;}@Overridepublic Void execute(CommandContext commandContext){Logger.getLogger(TaskFlowControlService.class).debug(String.format("executing activity: %s", _activity.getId()));ExecutionEntity execution = commandContext.getExecutionEntityManager().findExecutionById(_executionId);execution.setActivity(_activity);execution.performOperation(AtomicOperation.TRANSITION_CREATE_SCOPE);return null;}}


Q: 如何建立一個活動?

A: 建立活動可以調用processDefinition.createActivity(newActivityId),我們往往可以以某個使用中的物件為模板來複製一個新的活動,複製的方法是分別拷貝各個欄位的值:

protected ActivityImpl cloneActivity(ProcessDefinitionEntity processDefinition, ActivityImpl prototypeActivity,String newActivityId, String... fieldNames){ActivityImpl clone = processDefinition.createActivity(newActivityId);CloneUtils.copyFields(prototypeActivity, clone, fieldNames);return clone;}
拷貝欄位的代碼如下:

import org.apache.commons.lang.reflect.FieldUtils;import org.apache.log4j.Logger;import org.junit.Assert;public abstract class CloneUtils{public static void copyFields(Object source, Object target, String... fieldNames){Assert.assertNotNull(source);Assert.assertNotNull(target);Assert.assertSame(source.getClass(), target.getClass());for (String fieldName : fieldNames){try{Field field = FieldUtils.getField(source.getClass(), fieldName, true);field.setAccessible(true);field.set(target, field.get(source));}catch (Exception e){Logger.getLogger(CloneUtils.class).warn(e.getMessage());}}}}

一個樣本的用法是:
ActivityImpl clone = cloneActivity(processDefinition, prototypeActivity, cloneActivityId, "executionListeners","properties");

這個語句的意思是複製prototypeActivity對象的executionListeners和properties欄位。

Q: 如何?建立活動的持久化?

A: 一個辦法是將建立活動的類型、活動ID(activityId)、incomingTransitions、outgoingTransitions等資訊儲存起來,然後在ProcessEngine啟動的時候,在ProcessDefinition中註冊這些活動。


但還有一種更好的辦法,即只持久化“活動工廠”的資訊。譬如,我們根據step2活動建立一個step21活動,所有的資訊都一樣,這個時候只要持久化工廠類型(活動複製)、模板活動ID(step2)、新活動ID(step21),這種方法是極其節省空間的,而且簡化了代碼。比較複雜的例子,是將某個活動分裂成N個串列的會簽活動,這種情況只需要記錄模板活動ID、新活動ID數組就可以了,不需要記錄更多的資訊。如下示出一個建立N個使用者任務活動的例子:


public class ChainedActivitiesCreator extends RuntimeActivityCreatorSupport implements RuntimeActivityCreator{@Overridepublic ActivityImpl[] createActivities(ProcessEngine processEngine, ProcessDefinitionEntity processDefinition,RuntimeActivityDefinition info){info.setFactoryName(ChainedActivitiesCreator.class.getName());if (info.getCloneActivityIds() == null){info.setCloneActivityIds(CollectionUtils.arrayToList(new String[info.getAssignees().size()]));}return createActivities(processEngine, processDefinition, info.getProcessInstanceId(),info.getPrototypeActivityId(), info.getNextActivityId(), info.getAssignees(), info.getCloneActivityIds());}private ActivityImpl[] createActivities(ProcessEngine processEngine, ProcessDefinitionEntity processDefinition,String processInstanceId, String prototypeActivityId, String nextActivityId, List<String> assignees,List<String> activityIds){ActivityImpl prototypeActivity = ProcessDefinitionUtils.getActivity(processEngine, processDefinition.getId(),prototypeActivityId);List<ActivityImpl> activities = new ArrayList<ActivityImpl>();for (int i = 0; i < assignees.size(); i++){if (activityIds.get(i) == null){String activityId = createUniqueActivityId(processInstanceId, prototypeActivityId);activityIds.set(i, activityId);}ActivityImpl clone = createActivity(processEngine, processDefinition, prototypeActivity,activityIds.get(i), assignees.get(i));activities.add(clone);}ActivityImpl nextActivity = ProcessDefinitionUtils.getActivity(processEngine, processDefinition.getId(),nextActivityId);createActivityChain(activities, nextActivity);return activities.toArray(new ActivityImpl[0]);}}

這裡,RuntimeActivityDefinition代表一個工廠資訊,為了方便,不同工廠的個人化資訊存成了一個JSON字串,並會在載入的時候解析成一個Map:

public class RuntimeActivityDefinition{String _factoryName;String _processDefinitionId;String _processInstanceId;Map<String, Object> _properties = new HashMap<String, Object>();String _propertiesText;public void deserializeProperties() throws IOException{ObjectMapper objectMapper = new ObjectMapper();_properties = objectMapper.readValue(_propertiesText, Map.class);}public List<String> getAssignees(){return getProperty("assignees");}public String getCloneActivityId(){return getProperty("cloneActivityId");}//...}

一個節點分裂的工廠屬性:

{"sequential":true,"assignees":["bluejoe","alex"],"cloneActivityId":"2520001:step2:1419823449424-8","prototypeActivityId":"step2"}


Q: 說好的代碼呢?

A: 參見我在github上的開源項目OpenWebFlow,TaskFlowControlService.java是一個主要的類,它會調用一些creator和persistor來實現對象建立和持久化。該代碼已做過測試,測試案例參見AbstractProcessEngineToolTest。測試案例的方法說明如下:

  • testInsertTasksBefore:測試前加簽
  • testInsertTasksAfter:測試後加簽
  • testInsertTasksWithPersistence:測試加簽功能的持久化
  • testSplit:測試節點分裂
  • testMultiInstancesLoop:測試多執行個體節點(可用來實現串列、並行會簽)
  • testModelDeployment:測試流程模型部署
  • testMove:測試自由跳轉
  • testAcl:測試流程動態授權
  • testDelegation:測試代辦功能
  • testAlarm:測試催辦功能

AbstractProcessEngineToolTest有兩個衍生類別,分別是MemProcessEngineToolTest和SqlProcessEngineToolTest,它們分別測試基於記憶體和持久化的方案。持久化需要用到SQL資料庫,指令碼見src\test\java\openwebflow.sql。Activiti本身需要的SQL指令碼為src\test\java\activitidb.sql。

測試案例採用了如下的一個流程配合測試:




優雅的實現Activiti動態調整流程(自由跳轉、前進、後退、分裂、前加簽、後加簽等),含範例代碼!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.