ACTIVITI 是一個優秀開源軟件,通過閱讀源碼,我們不但可以了解工作流引擎執行的原理還可以增加個人的編碼功力。
ACTIVITI 所有執行過程都是采用命令模式進行執行。
本文主要描述流程引擎數據保存的過程。
流程引擎所有的操作都采用命令模式,使用命令執行器進行執行,命令執行器是一個采用攔截器鏈式執行模式。
1.命令執行器。
代碼為org.activiti.engine.impl.interceptor.CommandExecutor.
命令執行器的構造代碼如下:
1.獲取攔截器列表。
1.獲取客戶自定義前置攔截器。
這個需要實現CommandInterceptor接口,並配置到流程定義配置文件中。
2.獲取默認的攔截器。
protected Collection< ? extends CommandInterceptor> getDefaultCommandInterceptors() { List<CommandInterceptor> interceptors = new ArrayList<CommandInterceptor>(); interceptors.add(new LogInterceptor()); CommandInterceptor transactionInterceptor = createTransactionInterceptor(); if (transactionInterceptor != null) { interceptors.add(transactionInterceptor); } interceptors.add(new CommandContextInterceptor(commandContextFactory, this)); return interceptors; }
這個是獲取默認的攔截器。
這里有四個攔截器。
1.LogInterceptor日志攔截器,攔截器打印執行的日志。
2.事務攔截器。
3.CommandContextInterceptor 攔截器。
這個攔截器功能如下:
1.流程定義。
2.注入命令上下文,命令上下文包括數據只有代碼。
3.調用命令上下文close方法,執行數據保存。
4.命令執行攔截器,CommandInvoker 這個是攔截器最后的一個,為調用具體的命令。
3.獲取后置攔截器。
這個需要實現CommandInterceptor接口,並配置到流程定義配置文件中。
2.構建攔截器鏈。
基礎攔截器代碼:
public abstract class AbstractCommandInterceptor implements CommandInterceptor { /** will be initialized by the {@link org.activiti.engine.ProcessEngineConfiguration ProcessEngineConfiguration} */ protected CommandInterceptor next; @Override public CommandInterceptor getNext() { return next; } @Override public void setNext(CommandInterceptor next) { this.next = next; } }
攔截器調用setNext方法設置下一個攔截器。
protected CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) { if (chain==null || chain.isEmpty()) { throw new ActivitiException("invalid command interceptor chain configuration: "+chain); } for (int i = 0; i < chain.size()-1; i++) { chain.get(i).setNext( chain.get(i+1) ); } return chain.get(0); }
這里將攔截器列表構建成鏈的模式。
2.現在介紹一下命令的執行模式順序。
比如我們設置流程變量,參考代碼如下:
RuntimeService setVariable(String executionId, String variableName, Object value);
RuntimeServiceImpl 實現代碼:
Map<String, Object> variables = new HashMap<String, Object>(); variables.put(variableName, value); commandExecutor.execute(new SetExecutionVariablesCmd(executionId, variables, false));
這個commandExecutor到底是如何注入的。
我們可以看到這個RuntimeServiceImpl 擴展了類ServiceImpl。
我們在ProcessEngineConfigurationImpl 中看到如下代碼:
protected void initServices() { initService(repositoryService); initService(runtimeService); initService(historyService); initService(identityService); initService(taskService); initService(formService); initService(managementService); } protected void initService(Object service) { if (service instanceof ServiceImpl) { ((ServiceImpl)service).setCommandExecutor(commandExecutor); } }
這里注入了commandExecutor。
執行順序為:
1.執行前置攔截器,如果存在。
2.日志執行。
public class LogInterceptor extends AbstractCommandInterceptor { private static Logger log = LoggerFactory.getLogger(LogInterceptor.class); public <T> T execute(CommandConfig config, Command<T> command) { if (!log.isDebugEnabled()) { // do nothing here if we cannot log return next.execute(config, command); } log.debug(" "); log.debug("--- starting {} --------------------------------------------------------", command.getClass().getSimpleName()); try { return next.execute(config, command); } finally { log.debug("--- {} finished --------------------------------------------------------", command.getClass().getSimpleName()); log.debug(" "); } } }
參考日志代碼記錄日志,調用下一個攔截器(next.execute(config, command);),最后記錄日志。
3.執行事務。
3.執行CommandContext攔截器。
這個攔截器執行數據庫持久化。
try { // Push on stack Context.setCommandContext(context); Context.setProcessEngineConfiguration(processEngineConfiguration); return next.execute(config, command); } catch (Exception e) { context.exception(e); } finally { try { if (!contextReused) { context.close(); } } finally { // Pop from stack Context.removeCommandContext(); Context.removeProcessEngineConfiguration(); } }
在命令中並不執行數據庫持久化,持久化在此攔截器中調用context.close();執行。
4.執行后置攔截器,如果存在。
5.調用命令攔截器執行命令。