activiti总体框架分析

Engine解析

activiti包.png

1. org.activiti.engine

  1. 定义了流程管理服务的接口:RepositoryServiceRuntimeServiceFormServiceTaskServiceHistoryServiceIdentityServiceManagementService
  • 定义了引擎配置管理接口ProcessEngineConfiguration

  • 定义了activiti异常类ActivitiException

org.activiti.engine是activiti的核心功能,控制工作流的流转。几个核心的类如下图所示:

engine

1.1 ProcessEngine

ProcessEngine接口继承EngineServicesEngineServices包括很多工作流/BPM方法的服务,它们都是线程安全的。EngineServices提供的服务包括:

  • RepositoryService:提供了管理和控制流程定义的操作。

  • RuntimeService:提供了管理和控制流程实例的操作。

  • FormService:提供了管理流程表单的操作,即使不用FormService,activiti也可以完美运行。

  • TaskService:提供了任务管理的操作,包括实例任务挂起激活完成暂停查询

  • HistoryService:提供对历史流程,历史任务,历史变量的查询操作。

  • IdentityService:提供用户和组管理的操作(创建,更新,删除,查询...)。

  • ManagementService:提供了查询和管理异步操作(定时器,异步操作, 延迟暂停、激活等)的功能,它还可以查询到数据库的表和表的元数据。

EngineServices 代码如下所示:


  public interface EngineServices {

    RepositoryService getRepositoryService();

    RuntimeService getRuntimeService();

    FormService getFormService();

    TaskService getTaskService();

    HistoryService getHistoryService();

    IdentityService getIdentityService();

    ManagementService getManagementService();

    ProcessEngineConfiguration getProcessEngineConfiguration();
  }

ProcessEngine 代码如下所示:


  public interface ProcessEngine extends EngineServices {

    /** the version of the activiti library */
    public static String VERSION = "5.17.0.2";

    /** The name as specified in 'process-engine-name' in
     * the activiti.cfg.xml configuration file.
     * The default name for a process engine is 'default */
    String getName();

    void close();
  }

1.2 ProcessEngineConfiguration

ProcessEngineConfiguration是配置管理类,它管理的对象包括ProcessEngine,XXservice,数据库session等。ProcessEngineConfiguration的配置,activiti默认会从activiti.cfg.xml中读取,也可以在Spring的配置文件中读取。ProcessEngineConfiguration的实现包括:

  • ProcessEngineConfigurationImpl继承ProcessEngineConfiguration,实现了各种Service的初始化

  • StandaloneProcessEngineConfiguration是单独运行的流程引擎,继承ProcessEngineConfigurationImpl。代码如下:

  public class StandaloneProcessEngineConfiguration extends ProcessEngineConfigurationImpl {
    @Override
    protected CommandInterceptor createTransactionInterceptor() {
      return null;
    }
  }
  • StandaloneInMemProcessEngineConfiguration是单元测试时的辅助类,继承StandaloneProcessEngineConfiguration,默认使用H2内存数据库。数据库表会在引擎启动时创建,关闭时删除。代码如下所示:
  public class StandaloneInMemProcessEngineConfiguration extends StandaloneProcessEngineConfiguration {
   public StandaloneInMemProcessEngineConfiguration() {
     this.databaseSchemaUpdate = DB_SCHEMA_UPDATE_CREATE_DROP;
     this.jdbcUrl = "jdbc:h2:mem:activiti";
   }
  }
  • SpringProcessEngineConfiguration是Spring环境下使用的流程引擎。

  • JtaProcessEngineConfiguration单独运行的流程引擎,并使用JTA事务。

1.3 ActivitiException

activiti的基础异常类是org.activiti.engine.ActivitiException,一个非检查异常。Activiti的异常都是通过org.activiti.engine.ActivitiException抛出,但存在以下特殊情况:

  • ActivitiWrongDbException:当Activiti引擎发现数据库版本号和引擎版本号不一致时抛出。

  • ActivitiOptimisticLockingException:对同一数据进行并发方法并出现乐观锁时抛出。

  • ActivitiClassLoadingException:当无法找到需要加载的类或在加载类时出现了错误(比如,JavaDelegate,TaskListener等。

  • ActivitiObjectNotFoundException:当请求或操作的对应不存在时抛出。

  • ActivitiIllegalArgumentException:这个异常表示调用Activiti API时传入了一个非法的参数,可能是引擎配置中的非法值,或提供了一个非法制,或流程定义中使用的非法值。

  • ActivitiTaskAlreadyClaimedException:当任务已经被认领了,再调用taskService.claim(...)就会抛出。

  • BpmnError:流程部署错误,如流程定义文件不合法。

  • JobNotFoundException:JOB不存在。

2. org.activiti.engine.impl

  1. 实现了流程管理服务RepositoryServiceImpl, RuntimeServiceImpl, FormServiceImpl, TaskServiceImpl, HistoryServiceImpl, IdentityServiceImpl, ManagementServiceImpl
  • 实现流程虚拟机PVM

  • 数据持久化,脚本任务,条件表达式EL的解析等等

  • 命令接口的定义

命令接口包.png

2.1 org.activiti.engine.impl.ServiceImpl

  • XXService 的定义

org.activiti.engine.impl.ServiceImpl是流程管理服务的基类,它的派生类包括RepositoryServiceImpl, RuntimeServiceImpl, FormServiceImpl, TaskServiceImpl, HistoryServiceImpl, IdentityServiceImpl, ManagementServiceImpl,它定义了配置管理服务processEngineConfiguration、命令执行接口commandExecutor(activiti方法调用都通过命令模式)。源码如下所示:


  public class ServiceImpl {

    protected ProcessEngineConfigurationImpl processEngineConfiguration;

    public ServiceImpl() {
    }

    public ServiceImpl(ProcessEngineConfigurationImpl processEngineConfiguration) {
      this.processEngineConfiguration = processEngineConfiguration;
    }

    protected CommandExecutor commandExecutor;

    public CommandExecutor getCommandExecutor() {
      return commandExecutor;
    }

    public void setCommandExecutor(CommandExecutor commandExecutor) {
      this.commandExecutor = commandExecutor;
    }
  }

XXServiceImpl继承类org.activiti.engine.impl.ServiceImpl,并且实现对应的XXService接口。下面是RepositoryServiceImpl示例代码:


  public class RepositoryServiceImpl extends ServiceImpl implements RepositoryService {
  }

  • XXService的初始化

XXService的初始化在ProcessEngineConfigurationImpl中

   protected RepositoryService repositoryService = new RepositoryServiceImpl();  
   protected RuntimeService runtimeService = new RuntimeServiceImpl();
   protected HistoryService historyService = new HistoryServiceImpl(this);
   protected IdentityService identityService = new IdentityServiceImpl();
   protected TaskService taskService = new TaskServiceImpl(this);
   protected FormService formService = new FormServiceImpl();
   protected ManagementService managementService = new ManagementServiceImpl();

XXServicecommandExecutor初始化在ProcessEngineConfigurationImpl的initService中

 protected void initService(Object service) {
   if (service instanceof ServiceImpl) {
     ((ServiceImpl)service).setCommandExecutor(commandExecutor);
   }
 }

2.2 org.activiti.engine.impl.interceptor

org.activiti.engine.impl.interceptor定义了拦截器和命令。activiti里面所有的指令都是通过命令模式执行,在命令执行之前,可以切入多个拦截器。

拦截器
  • commandContext是命令上下文。

  • command是命令接口,command中定义了execute方法,代码如下所示:

 public interface Command <T> {
   T execute(CommandContext commandContext);
 }

  • CommandExecutor这个是命令的执行方法,CommandConfigCommandExecutor的配置。CommandExecutor代码如下所示:

 public interface CommandExecutor {

   /**
    * @return the default {@link CommandConfig}, used if none is provided.
    */
   CommandConfig getDefaultConfig();

   /**
    * Execute a command with the specified {@link CommandConfig}.
    */
   <T> T execute(CommandConfig config, Command<T> command);

   /**
    * Execute a command with the default {@link CommandConfig}.
    */
   <T> T execute(Command<T> command);

 }

  • CommandInterceptor拦截器,在命令执行之前进行拦截,一个命令可以有多个拦截器,这些拦截器通过链表链接起来顺序执行。CommandInterceptor代码如下:
 public interface CommandInterceptor {

   <T> T execute(CommandConfig config, Command<T> command);

   CommandInterceptor getNext();

   void setNext(CommandInterceptor next);

 }
  • commandExecutor到底是如何注入的?

RuntimeServiceImpl为例, RuntimeServiceImpl继承类ServiceImplServiceImpl包含CommandExecutor属性

ProcessEngineConfigurationImpl中有个init方法,里面有对于executor和intecerptor的初始化


 //  初始化各种服务
 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);
   }
 }

 //  初始化拦截器
 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 void initCommandExecutor() {
   if (commandExecutor==null) {
     CommandInterceptor first = initInterceptorChain(commandInterceptors);
     commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
   }
 }

2.3 org.activiti.engine.impl.delegate

org.activiti.engine.impl.delegate实现了监听器和事件处理,activiti 允许客户端代码介入流程的执行,为此提供了这个基础组件。

activiti5.16 用户手册的介绍,监听器事件处理

2.3.1 监听器

监听器可以捕获的事件包括:

  1. 流程实例的启动和结束
  • 选中一条连线
  • 节点的开始和结束
  • 网关的开始和结束
  • 中间事件的开始和结束
  • 开始时间结束或结束事件开始
执行监听器

DelegateInterceptor是事件拦截器接口,DelegateInvocation是事件调用接口,XXXInvocationDelegateInvocation的实现类,XXXInvocation里面包含监听接口XXXListener

  • 怎样添加监听

下面的流程定义文件包含2个监听器,event表示时间类型,class表示处理事件的java类。

 <extensionElements>
   <activiti:taskListener event="create" class="com.alfrescoblog.MyTest.imple.CreateTaskDelegate"></activiti:taskListener>
   <activiti:taskListener event="complete" class="com.alfrescoblog.MyTest.imple.MyJavaDelegate"></activiti:taskListener>
 </extensionElements>

CreateTaskDelegate是客户端实现的监听类,TaskListener``是activiti的监听接口。

package com.alfrescoblog.MyTest.imple;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

public class CreateTaskDelegate implements TaskListener {

  public void notify(DelegateTask delegateTask) {
    // TODO Auto-generated method stub
    System.out.println("创建任务啦!!"); 
  }

}

TaskListener代码如下所示:


 public interface TaskListener extends Serializable {

   String EVENTNAME_CREATE = "create";
   String EVENTNAME_ASSIGNMENT = "assignment";
   String EVENTNAME_COMPLETE = "complete";
   String EVENTNAME_DELETE = "delete";

   /**
    * Not an actual event, used as a marker-value for {@link TaskListener}s that should be called for all events,
    * including {@link #EVENTNAME_CREATE}, {@link #EVENTNAME_ASSIGNMENT} and {@link #EVENTNAME_COMPLETE} and {@link #EVENTNAME_DELETE}.
    */
   String EVENTNAME_ALL_EVENTS = "all";

   void notify(DelegateTask delegateTask);
 }

  • 监听怎样被注入的

BPMN流程文件部署的时候会注入各种listener。比如TaskListener在org.activiti.engine.impl.task.TaskDefinition的addTaskListener方法中被注入,代码如下:


 public void addTaskListener(String eventName, TaskListener taskListener) {
   if(TaskListener.EVENTNAME_ALL_EVENTS.equals(eventName)) {
     // In order to prevent having to merge the "all" tasklisteners with the ones for a specific eventName,
     // every time "getTaskListener()" is called, we add the listener explicitally to the individual lists
     this.addTaskListener(TaskListener.EVENTNAME_CREATE, taskListener);
     this.addTaskListener(TaskListener.EVENTNAME_ASSIGNMENT, taskListener);
     this.addTaskListener(TaskListener.EVENTNAME_COMPLETE, taskListener);
     this.addTaskListener(TaskListener.EVENTNAME_DELETE, taskListener);

   } else {
     List<TaskListener> taskEventListeners = taskListeners.get(eventName);
     if (taskEventListeners == null) {
       taskEventListeners = new ArrayList<TaskListener>();
       taskListeners.put(eventName, taskEventListeners);
     }
     taskEventListeners.add(taskListener);
   }
 }

  • 监听在什么时候触发的

以TaskListener为例,调用链:UserTaskActivityBehavior.execute()task.fireEvent(TaskListener.EVENTNAME_CREATE);DelegateInterceptor.handleInvocation()DefaultDelegateInterceptor.handleInvocation()DelegateInvocation.proceed()TaskListenerInvocation.invoke()TaskListener.notify()

UserTaskActivityBehavior 是任务新增、修改、删除行为,UserTask节点解析(UserTaskParseHandler.executeParse)的时候设置到activiti中,触发的代码还没找到。

 protected void executeParse(BpmnParse bpmnParse, UserTask userTask) {
   ActivityImpl activity = createActivityOnCurrentScope(bpmnParse, userTask, BpmnXMLConstants.ELEMENT_TASK_USER);

   activity.setAsync(userTask.isAsynchronous());
   activity.setExclusive(!userTask.isNotExclusive());

   TaskDefinition taskDefinition = parseTaskDefinition(bpmnParse, userTask, userTask.getId(), (ProcessDefinitionEntity) bpmnParse.getCurrentScope().getProcessDefinition());
   activity.setProperty(PROPERTY_TASK_DEFINITION, taskDefinition);
   activity.setActivityBehavior(bpmnParse.getActivityBehaviorFactory().createUserTaskActivityBehavior(userTask, taskDefinition));
 }

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容