activiti和设计模式(2.1)
activiti中Command的执行的过程,也是一个设计模式来进行控制的,就是责任链设计模式,或者:Interpreter pattern.
首先是启动的代码:
//调用方:
ProcessInstance ins = runtimeService.startProcessInstanceById(workFlowId, formId,variablesObject);
//调用的入口:
public ProcessInstance startProcessInstanceById(String processDefinitionId,
String businessKey, Map<String, Object> variables) {
return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(null,
processDefinitionId, businessKey, variables));
}
从图中可以看出:CommandExecutor 已经包含了执行所需要的全部的内容,我们看一下执行的代码:
@Override
public <T> T execute(Command<T> command) {
return execute(defaultConfig, command);
}
@Override
public <T> T execute(CommandConfig config, Command<T> command) {
return first.execute(config, command);
}
//这里我们可以看到,执行的过程进入了某一个链中。
这个链总共有三个类构成:
org.activiti.engine.impl.interceptor.LogInterceptor
org.activiti.engine.impl.interceptor.CommandContextInterceptor
org.activiti.engine.impl.interceptor.CommandInvoker
这三个类全部实现了接口:CommandInterceptor
public interface CommandInterceptor {
<T> T execute(CommandConfig config, Command<T> command);
CommandInterceptor getNext();
void setNext(CommandInterceptor next);
}
通过这个代码的 setNext方法,这三个类构成了一个执行链,在引擎初始化的时候,能够发现这个执行链构造和初始化的代码:
protected void initCommandInvoker() {
if (commandInvoker==null) {
commandInvoker = new CommandInvoker();//③
}
}
protected void initCommandInterceptors() {
if (commandInterceptors==null) {
commandInterceptors = new ArrayList<CommandInterceptor>();
if (customPreCommandInterceptors!=null) {
commandInterceptors.addAll(customPreCommandInterceptors);
}
commandInterceptors.addAll(getDefaultCommandInterceptors());
if (customPostCommandInterceptors!=null) {
commandInterceptors.addAll(customPostCommandInterceptors);
}
commandInterceptors.add(commandInvoker);
}
}
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;
}
//初始化这条链
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);
}
// commandExecutor 初始化完成
protected void initCommandExecutor() {
if (commandExecutor==null) {
CommandInterceptor first = initInterceptorChain(commandInterceptors);
commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
}
}
这个三个拦截链都做了什么呢?第一个就是日志记录,虽然个人感觉比较的无聊,但是也可能是一个扩展的示例:LogInterceptor
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("\n");
log.debug("--- starting {} --------------------------------------------------------", command.getClass().getSimpleName());
try {
return next.execute(config, command);
} finally {
log.debug("--- {} finished --------------------------------------------------------", command.getClass().getSimpleName());
log.debug("\n");
}
}
第二个链:CommandContextInterceptor 主要是构建命令运行的执行的环境:
public <T> T execute(CommandConfig config, Command<T> command) {
CommandContext context = Context.getCommandContext();
boolean contextReused = false;
// We need to check the exception, because the transaction can be in a rollback state,
// and some other command is being fired to compensate (eg. decrementing job retries)
if (!config.isContextReusePossible() || context == null || context.getException() != null) {
context = commandContextFactory.createCommandContext(command);
}
else {
log.debug("Valid context found. Reusing it for the current command '{}'", command.getClass().getCanonicalName());
contextReused = true;
}
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.removeBpmnOverrideContext();
}
}
return null;
}
从这个环境构造,可以看出来两个问题:
- context的组织方式,是根据Command进行的,并且Context是通过stack进行组织的。
- 既然context是根据stack组织的,说明有压栈,出栈的操作,也就说明Command之间存在嵌套的可能性。
第三个链:CommandInvoker 命令行的执行:
@Override
public <T> T execute(CommandConfig config, Command<T> command) {
return command.execute(Context.getCommandContext());
}
可以看到最终执行的过程,还是到了每一个的command类中,这也是符合预期的。此例中最终进入StartProcessInstanceCmd类中,执行代码:
public ProcessInstance execute(CommandContext commandContext) {
DeploymentManager deploymentManager = commandContext
.getProcessEngineConfiguration()
.getDeploymentManager();
// Find the process definition
ProcessDefinitionEntity processDefinition = null;
if (processDefinitionId != null) {
processDefinition = deploymentManager.findDeployedProcessDefinitionById(processDefinitionId);
}
。。。。。。。。
// Start the process instance
ExecutionEntity processInstance = processDefinition.createProcessInstance(businessKey);
。。。。。。。。
processInstance.start();
return processInstance;
}
可以看出来这个是 Interpreter pattern 和 Command Pattern 联合使用的一种情况,就目的而言,试分析一二:
总结来自:
1)一个产品或者一个项目,很少是一个人开发出来的,大多都涉及到协同工作。但是既然是一个框架,那么总体上面的需要有一个规范,利于大家的开发,利于大家的协调。这个就是架构的意义所在。 有了具体的架构的约束,加入一些基础的组件,基本上能够把实现的大体的过程规划出来,这样这个框架的整体的风格也就确定了。就像Activiti做的这样,明确以Command作为基本开发模型,辅之以Event-Listener,这样编程风格的整体性得到了保证。
2)使用命令模式和责任链的好处 职责分离,解耦。有了Command,各个Service从角色上说只是一些协调者或者控制者,不需要知道具体怎么做,他只是把任务交给了各个命令。便于封装每一个的功能
3)解耦之后,随之带来的一个好处,就是扩展或者说灵活性的增加,我们可以把自己扩展的动作按照同样的方式,封装成一个一个的command,更加的便于理解和别人的使用。大大的增加activiti的生态。
- 上一篇 activiti和设计模式(2)
- 下一篇 activiti和设计模式(3)