activiti總體框架分析

Engine解析

activiti包.png

1. org.activiti.engine

  1. 定義了流程管理服務(wù)的接口:RepositoryServiceRuntimeService式廷、 FormService郭怪、TaskService晨仑、HistoryService嘉赎、IdentityService膝晾、 ManagementService 米辐。
  • 定義了引擎配置管理接口ProcessEngineConfiguration胸完。

  • 定義了activiti異常類ActivitiException

org.activiti.engine是activiti的核心功能翘贮,控制工作流的流轉(zhuǎn)赊窥。幾個(gè)核心的類如下圖所示:

engine

1.1 ProcessEngine

ProcessEngine接口繼承EngineServicesEngineServices包括很多工作流/BPM方法的服務(wù)狸页,它們都是線程安全的锨能。EngineServices提供的服務(wù)包括:

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

  • RuntimeService:提供了管理和控制流程實(shí)例的操作芍耘。

  • FormService:提供了管理流程表單的操作址遇,即使不用FormService,activiti也可以完美運(yùn)行斋竞。

  • TaskService:提供了任務(wù)管理的操作傲隶,包括實(shí)例任務(wù)掛起激活窃页、完成跺株、暫停查詢脖卖。

  • HistoryService:提供對(duì)歷史流程乒省,歷史任務(wù),歷史變量的查詢操作畦木。

  • IdentityService:提供用戶和組管理的操作(創(chuàng)建袖扛,更新,刪除十籍,查詢...)蛆封。

  • ManagementService:提供了查詢和管理異步操作(定時(shí)器,異步操作勾栗, 延遲暫停惨篱、激活等)的功能,它還可以查詢到數(shù)據(jù)庫(kù)的表和表的元數(shù)據(jù)围俘。

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是配置管理類砸讳,它管理的對(duì)象包括ProcessEngine琢融,XXservice,數(shù)據(jù)庫(kù)session等簿寂。ProcessEngineConfiguration的配置漾抬,activiti默認(rèn)會(huì)從activiti.cfg.xml中讀取,也可以在Spring的配置文件中讀取常遂。ProcessEngineConfiguration的實(shí)現(xiàn)包括:

  • ProcessEngineConfigurationImpl繼承ProcessEngineConfiguration纳令,實(shí)現(xiàn)了各種Service的初始化

  • StandaloneProcessEngineConfiguration是單獨(dú)運(yùn)行的流程引擎,繼承ProcessEngineConfigurationImpl克胳。代碼如下:

  public class StandaloneProcessEngineConfiguration extends ProcessEngineConfigurationImpl {
    @Override
    protected CommandInterceptor createTransactionInterceptor() {
      return null;
    }
  }
  • StandaloneInMemProcessEngineConfiguration是單元測(cè)試時(shí)的輔助類泊碑,繼承StandaloneProcessEngineConfiguration,默認(rèn)使用H2內(nèi)存數(shù)據(jù)庫(kù)毯欣。數(shù)據(jù)庫(kù)表會(huì)在引擎啟動(dòng)時(shí)創(chuàng)建,關(guān)閉時(shí)刪除臭脓。代碼如下所示:
  public class StandaloneInMemProcessEngineConfiguration extends StandaloneProcessEngineConfiguration {
   public StandaloneInMemProcessEngineConfiguration() {
     this.databaseSchemaUpdate = DB_SCHEMA_UPDATE_CREATE_DROP;
     this.jdbcUrl = "jdbc:h2:mem:activiti";
   }
  }
  • SpringProcessEngineConfiguration是Spring環(huán)境下使用的流程引擎酗钞。

  • JtaProcessEngineConfiguration單獨(dú)運(yùn)行的流程引擎,并使用JTA事務(wù)来累。

1.3 ActivitiException

activiti的基礎(chǔ)異常類是org.activiti.engine.ActivitiException砚作,一個(gè)非檢查異常。Activiti的異常都是通過(guò)org.activiti.engine.ActivitiException拋出嘹锁,但存在以下特殊情況:

  • ActivitiWrongDbException:當(dāng)Activiti引擎發(fā)現(xiàn)數(shù)據(jù)庫(kù)版本號(hào)和引擎版本號(hào)不一致時(shí)拋出葫录。

  • ActivitiOptimisticLockingException:對(duì)同一數(shù)據(jù)進(jìn)行并發(fā)方法并出現(xiàn)樂(lè)觀鎖時(shí)拋出。

  • ActivitiClassLoadingException:當(dāng)無(wú)法找到需要加載的類或在加載類時(shí)出現(xiàn)了錯(cuò)誤(比如领猾,JavaDelegate米同,TaskListener等。

  • ActivitiObjectNotFoundException:當(dāng)請(qǐng)求或操作的對(duì)應(yīng)不存在時(shí)拋出摔竿。

  • ActivitiIllegalArgumentException:這個(gè)異常表示調(diào)用Activiti API時(shí)傳入了一個(gè)非法的參數(shù)面粮,可能是引擎配置中的非法值,或提供了一個(gè)非法制继低,或流程定義中使用的非法值熬苍。

  • ActivitiTaskAlreadyClaimedException:當(dāng)任務(wù)已經(jīng)被認(rèn)領(lǐng)了,再調(diào)用taskService.claim(...)就會(huì)拋出袁翁。

  • BpmnError:流程部署錯(cuò)誤柴底,如流程定義文件不合法。

  • JobNotFoundException:JOB不存在粱胜。

2. org.activiti.engine.impl

  1. 實(shí)現(xiàn)了流程管理服務(wù)RepositoryServiceImpl, RuntimeServiceImpl, FormServiceImpl, TaskServiceImpl, HistoryServiceImpl, IdentityServiceImpl, ManagementServiceImpl
  • 實(shí)現(xiàn)流程虛擬機(jī)PVM

  • 數(shù)據(jù)持久化柄驻,腳本任務(wù),條件表達(dá)式EL的解析等等

  • 命令接口的定義

命令接口包.png

2.1 org.activiti.engine.impl.ServiceImpl

  • XXService 的定義

org.activiti.engine.impl.ServiceImpl是流程管理服務(wù)的基類焙压,它的派生類包括RepositoryServiceImpl, RuntimeServiceImpl, FormServiceImpl, TaskServiceImpl, HistoryServiceImpl, IdentityServiceImpl, ManagementServiceImpl凿歼,它定義了配置管理服務(wù)processEngineConfiguration褪迟、命令執(zhí)行接口commandExecutor(activiti方法調(diào)用都通過(guò)命令模式)。源碼如下所示:


  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答憔,并且實(shí)現(xiàn)對(duì)應(yīng)的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里面所有的指令都是通過(guò)命令模式執(zhí)行虐拓,在命令執(zhí)行之前心俗,可以切入多個(gè)攔截器。

攔截器
  • commandContext是命令上下文蓉驹。

  • command是命令接口城榛,command中定義了execute方法,代碼如下所示:

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

  • CommandExecutor這個(gè)是命令的執(zhí)行方法态兴,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攔截器,在命令執(zhí)行之前進(jìn)行攔截瞻润,一個(gè)命令可以有多個(gè)攔截器喘垂,這些攔截器通過(guò)鏈表鏈接起來(lái)順序執(zhí)行。CommandInterceptor代碼如下:
 public interface CommandInterceptor {

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

   CommandInterceptor getNext();

   void setNext(CommandInterceptor next);

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

RuntimeServiceImpl為例正勒, RuntimeServiceImpl繼承類ServiceImplServiceImpl包含CommandExecutor屬性

ProcessEngineConfigurationImpl中有個(gè)init方法傻铣,里面有對(duì)于executor和intecerptor的初始化


 //  初始化各種服務(wù)
 protected void initServices() {
     initService(repositoryService);
     initService(runtimeService);
     initService(historyService);
     initService(identityService);
     initService(taskService);
     initService(formService);
     initService(managementService);
 }

 //  初始化服務(wù)方法  
 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);
     }
 }

 //  將攔截器初始化成鏈?zhǔn)浇Y(jié)構(gòu)
 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實(shí)現(xiàn)了監(jiān)聽(tīng)器和事件處理章贞,activiti 允許客戶端代碼介入流程的執(zhí)行,為此提供了這個(gè)基礎(chǔ)組件非洲。

activiti5.16 用戶手冊(cè)的介紹鸭限,監(jiān)聽(tīng)器事件處理两踏。

2.3.1 監(jiān)聽(tīng)器

監(jiān)聽(tīng)器可以捕獲的事件包括:

  1. 流程實(shí)例的啟動(dòng)和結(jié)束
  • 選中一條連線
  • 節(jié)點(diǎn)的開(kāi)始和結(jié)束
  • 網(wǎng)關(guān)的開(kāi)始和結(jié)束
  • 中間事件的開(kāi)始和結(jié)束
  • 開(kāi)始時(shí)間結(jié)束或結(jié)束事件開(kāi)始
執(zhí)行監(jiān)聽(tīng)器

DelegateInterceptor是事件攔截器接口里覆,DelegateInvocation是事件調(diào)用接口,XXXInvocationDelegateInvocation的實(shí)現(xiàn)類缆瓣,XXXInvocation里面包含監(jiān)聽(tīng)接口XXXListener喧枷。

  • 怎樣添加監(jiān)聽(tīng)

下面的流程定義文件包含2個(gè)監(jiān)聽(tīng)器,event表示時(shí)間類型弓坞,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是客戶端實(shí)現(xiàn)的監(jiān)聽(tīng)類,TaskListener``是activiti的監(jiān)聽(tīng)接口渡冻。

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("創(chuàng)建任務(wù)啦F莅狻!"); 
  }

}

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);
 }

  • 監(jiān)聽(tīng)怎樣被注入的

BPMN流程文件部署的時(shí)候會(huì)注入各種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);
   }
 }

  • 監(jiān)聽(tīng)在什么時(shí)候觸發(fā)的

以TaskListener為例珠增,調(diào)用鏈:UserTaskActivityBehavior.execute()task.fireEvent(TaskListener.EVENTNAME_CREATE);DelegateInterceptor.handleInvocation()DefaultDelegateInterceptor.handleInvocation()DelegateInvocation.proceed()TaskListenerInvocation.invoke()TaskListener.notify()

UserTaskActivityBehavior 是任務(wù)新增、修改砍艾、刪除行為蒂教,UserTask節(jié)點(diǎn)解析(UserTaskParseHandler.executeParse)的時(shí)候設(shè)置到activiti中,觸發(fā)的代碼還沒(méi)找到脆荷。

 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));
 }

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凝垛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蜓谋,更是在濱河造成了極大的恐慌梦皮,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桃焕,死亡現(xiàn)場(chǎng)離奇詭異剑肯,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)观堂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門让网,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人型将,你說(shuō)我怎么就攤上這事〖雠埃” “怎么了七兜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)福扬。 經(jīng)常有香客問(wèn)我腕铸,道長(zhǎng),這世上最難降的妖魔是什么铛碑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任狠裹,我火速辦了婚禮,結(jié)果婚禮上汽烦,老公的妹妹穿的比我還像新娘涛菠。我一直安慰自己,他們只是感情好撇吞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布俗冻。 她就那樣靜靜地躺著,像睡著了一般牍颈。 火紅的嫁衣襯著肌膚如雪迄薄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天煮岁,我揣著相機(jī)與錄音讥蔽,去河邊找鬼涣易。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冶伞,可吹牛的內(nèi)容都是我干的新症。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼碰缔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼账劲!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起金抡,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瀑焦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后梗肝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體榛瓮,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年巫击,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了禀晓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坝锰,死狀恐怖粹懒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布晃琳,位于F島的核電站辐真,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望导街。 院中可真熱鬧,春花似錦纤子、人聲如沸搬瑰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)跌捆。三九已至,卻和暖如春象颖,著一層夾襖步出監(jiān)牢的瞬間佩厚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工说订, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抄瓦,地道東北人潮瓶。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像钙姊,于是被迫代替她去往敵國(guó)和親毯辅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容