最近对Activiti作了一些深刻的研究,对Activiti的流程机制有了些理解,对动态调整流程也有了一些实践方法。java
如今好好总结一下,一来是对这段时间本身辛苦探索的一个记录,二来也是为后来者指指路~~~数据库
以下内容准备采用QA的方式写,不少问题都是当初本身极疑惑的问题,但愿能为你们解惑!apache
A:能够!能够动态更改流程指向,或者建立新的节点,等等。。。数组
A: 必需要实现持久化!不然一旦应用重启,你的流程就犯糊涂了!譬如,你建立了一个新节点,但因为没有持久化,重启以后流程引擎找不到那个新节点了。。。app
A: 除了持久化以外,还记住尽可能不要由于临时调整直接更改现有活动(没准这个活动后面还要照常使用呢!),这种状况能够考虑克隆。第三,不要直接操做数据库,或者SqlSession,记住本身写Command!参见我前面的另一篇文章。以下代码示出执行某个activity后续流程的Cmd:ide
public class CreateAndTakeTransitionCmd implements Command<java.lang.Void> { private ActivityImpl _activity; private String _executionId; public CreateAndTakeTransitionCmd(String executionId, ActivityImpl activity) { _executionId = executionId; _activity = activity; } @Override public 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; } }
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");
A: 一个办法是将新建活动的类型、活动ID(activityId)、incomingTransitions、outgoingTransitions等信息保存起来,而后在ProcessEngine启动的时候,在ProcessDefinition中注册这些活动。spa
但还有一种更好的办法,即只持久化“活动工厂”的信息。譬如,咱们根据step2活动建立一个step21活动,全部的信息都同样,这个时候只要持久化工厂类型(活动克隆)、模板活动ID(step2)、新活动ID(step21),这种方法是极其节省空间的,并且简化了代码。比较复杂的例子,是将某个活动分裂成N个串行的会签活动,这种状况只须要记录模板活动ID、新活动ID数组就能够了,不须要记录更多的信息。以下示出一个建立N个用户任务活动的例子:.net
public class ChainedActivitiesCreator extends RuntimeActivityCreatorSupport implements RuntimeActivityCreator { @Override public 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:prototype
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"}