六十分鐘入門(mén)Activiti框架原理

本文基于一個(gè)簡(jiǎn)單的Demo流程介紹了Activiti框架啟動(dòng)、部署窟社、運(yùn)行過(guò)程祟滴。

Demo準(zhǔn)備

流程圖文件:

<?xml version="1.0" encoding="UTF-8"?>
<definitions  xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
   <process id="hello" name="hello" isExecutable="true">
        <!-- 流程開(kāi)始節(jié)點(diǎn) -->
        <startEvent id="start" name="Start" ></startEvent>
        <!-- serviceTask:執(zhí)行me.likeyao.activiti.demo.HelloWorld的execute方法,打印hello world -->
        <serviceTask id="helloworld" name="helloworld" activiti:class="me.likeyao.activiti.demo.HelloWorld"/>
        <!-- 流程結(jié)束節(jié)點(diǎn) -->
        <endEvent id="end" name="End"></endEvent>
        <!-- 流程遷移線:開(kāi)始節(jié)點(diǎn)到serviceTask節(jié)點(diǎn) -->
        <sequenceFlow id="sid-1" sourceRef="start" targetRef="helloworld"></sequenceFlow>
        <!-- 流程遷移線:serviceTask節(jié)點(diǎn)到結(jié)束節(jié)點(diǎn) -->
        <sequenceFlow id="sid-3" sourceRef="helloworld" targetRef="end"></sequenceFlow>
    </process>
</definitions>

流程圖:

demo流程

代碼:

public class App {
    public static void main(String[] args) {
        //創(chuàng)建流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //部署流程圖
        processEngine.getRepositoryService().createDeployment().addClasspathResource("hello.bpmn20.xml").deploy();
        //發(fā)起流程
        processEngine.getRuntimeService().startProcessInstanceByKey("hello");
    }
}


public class HelloWorld implements JavaDelegate{
    public void execute(DelegateExecution execution) throws Exception {
        System.out.println("Hello world!");
    }
}

Demo實(shí)現(xiàn)的功能是發(fā)起一個(gè)流程这弧,執(zhí)行到流程的serviceTask節(jié)點(diǎn)時(shí),打印Hello world虚汛!匾浪,然后流程結(jié)束。

源碼版本:5.22.0

框架初始化

ProcessEngine類(lèi)圖

ProcessEngine

ProcessEngine是Activiti框架的門(mén)面卷哩,ProcessEngine本身不提供任何功能户矢,通過(guò)getXXXService方法可以獲取到對(duì)應(yīng)的Service對(duì)象執(zhí)行操作。Demo中涉及到的兩個(gè)Service:

  • RepositoryService:流程定義和流程部署相關(guān)功能殉疼。
  • RuntimeService:流程實(shí)例相關(guān)功能(發(fā)起流程梯浪、獲取流程實(shí)例變量)。

ProcessEngineConfiguration

ProcessEngineConfiguration負(fù)責(zé)Activiti框架的屬性配置瓢娜、初始化工作挂洛,初始化入口是buildProcessEngine方法,所有Activiti框架運(yùn)行時(shí)需要用到的組件基本都在這里初始化:

public ProcessEngine buildProcessEngine() {
    init();
    return new ProcessEngineImpl(this);
}

protected void init() {
    initConfigurators();
    configuratorsBeforeInit();
    initProcessDiagramGenerator();
    initHistoryLevel();
    initExpressionManager();
    initDataSource();
    initVariableTypes();
    initBeans();
    initFormEngines();
    initFormTypes();
    initScriptingEngines();
    initClock();
    initBusinessCalendarManager();
    initCommandContextFactory();
    initTransactionContextFactory();
    initCommandExecutors();
    initServices();
    initIdGenerator();
    initDeployers();
    initJobHandlers();
    initJobExecutor();
    initAsyncExecutor();
    initTransactionFactory();
    initSqlSessionFactory();
    initSessionFactories();
    initJpa();
    initDelegateInterceptor();
    initEventHandlers();
    initFailedJobCommandFactory();
    initEventDispatcher();
    initProcessValidator();
    initDatabaseEventLogging();
    configuratorsAfterInit();
}

這里有一個(gè)擴(kuò)展點(diǎn):ProcessEngineConfigurator眠砾。

public interface ProcessEngineConfigurator {
    //組件初始化前
    void beforeInit(ProcessEngineConfigurationImpl processEngineConfiguration);
    //組件初始化后
    void configure(ProcessEngineConfigurationImpl processEngineConfiguration);
    //優(yōu)先級(jí)
    int getPriority();
}

在init初始化方法中虏劲,initConfigurators方法通過(guò)ServiceLoader加載ProcessEngineConfigurator。隨后在configuratorsBeforeInit和configuratorsAfterInit方法中分別調(diào)用ProcessEngineConfigurator的beforeInit和configure方法,使用戶(hù)可以在ProcessEngineConfiguration初始化前后編程式的修改屬性柒巫,替換Activiti默認(rèn)組件励堡。

流程部署

流程部署實(shí)現(xiàn)的功能是將xml格式的流程圖,轉(zhuǎn)化為Activiti框架運(yùn)行時(shí)依賴(lài)的流程定義對(duì)象堡掏。

RepositoryService

RepositoryService類(lèi)圖

Demo中通過(guò)以下代碼部署了一個(gè)流程:

processEngine.getRepositoryService().createDeployment().addClasspathResource("hello.bpmn20.xml").deploy();

createDeployment方法中創(chuàng)建了DeploymentBuilder對(duì)象应结,DeploymentBuilder對(duì)象負(fù)責(zé)讀取指定路徑的流程圖xml文件的內(nèi)容(byte數(shù)組),并緩存在DeploymentEntity對(duì)象中:

public DeploymentBuilder addInputStream(String resourceName, InputStream inputStream) {
    ...
    byte[] bytes = IoUtil.readInputStream(inputStream, resourceName);
    ResourceEntity resource = new ResourceEntity();
    resource.setName(resourceName);
    resource.setBytes(bytes);
    deployment.addResource(resource);
    return this;
}

最終DeploymentBuilder的deploy方法會(huì)調(diào)用RepositoryService的deploy方法泉唁,完成流程部署:

public Deployment deploy() {
    return repositoryService.deploy(this);
}

CommandExecutor

在RepositoryService的deploy方法中鹅龄,使用了CommandExecutor對(duì)象:

public Deployment deploy(DeploymentBuilderImpl deploymentBuilder) {
    return commandExecutor.execute(new DeployCmd<Deployment>(deploymentBuilder));
}
CommandExecutor類(lèi)圖

在Activiti中,大部分操作都以Command模式實(shí)現(xiàn)亭畜,例如部署流程圖的DeployCmd扮休。CommandExecutor封裝了一系列的CommandInterceptor,在內(nèi)部形成CommandInterceptor鏈拴鸵,在命令執(zhí)行前后做了攔截玷坠。Activiti框架提供了一些
CommandInterceptor實(shí)現(xiàn):

名稱(chēng) 作用
CommandContextInterceptor 用于生成命令執(zhí)行的上下文(CommandContext)。
LogInterceptor 開(kāi)啟日志Debug級(jí)別后劲藐,打印日志八堡。
JtaTransactionInterceptor 開(kāi)啟Jta事務(wù)

引入activiti-spring包,通過(guò)SpringTransactionInterceptor引入Spring的事務(wù)支持瘩燥。

CommandExecutor在ProcessEngineConfigurationImpl的initCommandExecutors方法中初始化:

protected void initCommandExecutors() {
    initDefaultCommandConfig();
    initSchemaCommandConfig();
    initCommandInvoker();
    initCommandInterceptors();
    initCommandExecutor();
}

可以設(shè)置ProcessEngineConfigurationImpl的customPreCommandInterceptors和customPostCommandInterceptors屬性,添加自定義的CommandInterceptor:

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

這里的pre和post是指Activiti框架getDefaultCommandInterceptors()的前后不同。

CommandInvoker是CommandInterceptor鏈的最后一個(gè)對(duì)象厉膀,負(fù)責(zé)調(diào)用Command:

public class CommandInvoker extends AbstractCommandInterceptor {
    @Override
    public <T> T execute(CommandConfig config, Command<T> command) {
        return command.execute(Context.getCommandContext());
    }
}

CommandContext

CommandContext類(lèi)圖

CommandContext是Activit框架Command執(zhí)行的上下文,主要包含各種SessionFactory:

sessionFactories = processEngineConfiguration.getSessionFactories();

SessionFactory負(fù)責(zé)生成Session二拐,Session是Activiti操作持久化對(duì)象的統(tǒng)一接口:

名稱(chēng) 作用
ProcessDefinitionEntityManager 流程定義相關(guān)讀寫(xiě)操作服鹅。
ExecutionEntityManager 流程實(shí)例相關(guān)讀寫(xiě)操作。
DefaultHistoryManager 歷史記錄相關(guān)讀寫(xiě)操作

CommandContext的生命周期

CommandConext在CommandContextInterceptor中創(chuàng)建百新,在finally代碼塊中銷(xiāo)毀:

public <T> T execute(CommandConfig config, Command<T> command) {
    //首先嘗試從線程上下文的棧中獲取CommandContext
    CommandContext context = Context.getCommandContext();
    boolean contextReused = false;
    //什么時(shí)候創(chuàng)建新的CommandContext企软?
    //1、CommandConfig中指定了不復(fù)用CommandContext
    //2饭望、當(dāng)前線程上下文中不存在CommandConext
    //3仗哨、當(dāng)前線程上下文中的CommandConext已經(jīng)拋出異常
    if (!config.isContextReusePossible() || context == null || context.getException() != null) { 
        context = commandContextFactory.createCommandContext(command);      }  
    else {
        contextReused = true;
    }

    try {
        //將前面獲取到的CommandContext入棧
        Context.setCommandContext(context);
        Context.setProcessEngineConfiguration(processEngineConfiguration);
        //執(zhí)行下一個(gè)interceptor,在CommandInvoker中可以通過(guò)Context.getCommandContext()獲取線程上下文中的CommandContext
        return next.execute(config, command);
    } catch (Exception e) {
        //記錄異常信息
        context.exception(e);
    } finally {
        try {
            //如果CommandContext不可復(fù)用铅辞,用完直接關(guān)閉
            if (!contextReused) {
                context.close();
            }
        } finally {
            //出棧操作
            Context.removeCommandContext();
            Context.removeProcessEngineConfiguration();
            Context.removeBpmnOverrideContext();
        }
    }
    
    return null;
}

Activiti的框架可以在一個(gè)Command的執(zhí)行過(guò)程中厌漂,調(diào)用另外一個(gè)Command,所以會(huì)出現(xiàn)是否需要復(fù)用CommandContext的選項(xiàng)斟珊,默認(rèn)值為true苇倡。

流程的解析

在DeployCmd中,首先調(diào)用DeploymentEntityManager持久化存儲(chǔ)DeploymentEntity對(duì)象:

commandContext.getDeploymentEntityManager().insertDeployment(deployment);

然后調(diào)用DeploymentManager部署流程(流程解析):

commandContext.getProcessEngineConfiguration().getDeploymentManager().deploy(deployment, deploymentSettings);
DeploymentEntityManager
DeploymentEntityManager類(lèi)圖

DeploymentEntityManager的deploy方法中循環(huán)調(diào)用Deployer對(duì)象的deploy方法,Activiti默認(rèn)的Deployer是BpmnDeployer旨椒。

另外DeploymentEntityManager中還緩存了解析好的流程定義對(duì)象和Bpmn模型對(duì)象晓褪。

Activiti持久化的是流程圖xml文件,每次系統(tǒng)重新啟動(dòng)都要執(zhí)行一次“deploy”操作综慎,生成ProcessDefinitionEntity對(duì)象涣仿。

BpmnDeployer
BpmnDeployer類(lèi)圖

BpmnDeployer的deploy方法中包含幾個(gè)操作(代碼縮略版):

public void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings) {
    ...
    BpmnParse bpmnParse = bpmnParser.createParse().sourceInputStream(inputStream).setSourceSystemId(resourceName).deployment(deployment).name(resourceName);
    bpmnParse.execute();
    for (ProcessDefinitionEntity processDefinition: bpmnParse.getProcessDefinitions()) {
        if (deployment.isNew()) {
            ProcessDefinitionEntity latestProcessDefinition = ...
            if (latestProcessDefinition != null) {
                processDefinitionVersion = latestProcessDefinition.getVersion() + 1;
            }else{
                processDefinitionVersion = 1;
            }
            processDefinition.setId(idGenerator.getNextId());
            dbSqlSession.insert(processDefinition);
        }
        ...
    }
}
  • 通過(guò)BpmnParser對(duì)象創(chuàng)建BpmnParse。
  • 調(diào)用BpmnParse的execute方法寥粹,將inputStream中的流程圖轉(zhuǎn)化為ProcessDefinitionEntity变过。
  • 持久化ProcessDefinitionEntity對(duì)象。
BpmnParse
BpmnParse類(lèi)圖

在BpmnParse的execute中完成了xml文件到ProcessDefinitionEntity對(duì)象的轉(zhuǎn)化:

public BpmnParse execute() {
    //xml->bpmnModel
    bpmnModel = converter.convertToBpmnModel(streamSource, validateSchema, enableSafeBpmnXml, encoding);
    //bpmnModel-> ProcessDefinitionEntity
    transformProcessDefinitions();
}

protected void transformProcessDefinitions() {
    for (Process process : bpmnModel.getProcesses()) {
        bpmnParserHandlers.parseElement(this, process);
    }
}

在流程定義解析過(guò)程中涝涤,會(huì)涉及到兩套模型:

  • Bpmn模型(由BpmnXMLConverter完成轉(zhuǎn)換)
  • PVM模型(由BpmnParseHandlers完成轉(zhuǎn)換)

Bpmn模型

Bpmn模型

PVM模型

PVM模型

Bpmn模型更偏向于xml節(jié)點(diǎn)的描述媚狰,PVM模型是運(yùn)行時(shí)模型。Bpmn模型中的ServiceTask阔拳、StartEvent等會(huì)統(tǒng)一映射轉(zhuǎn)換為PVM的ActivityImpl對(duì)象崭孤,ServiceTask和StartEvent等節(jié)點(diǎn)行為上的差別,體現(xiàn)在ActivityImpl對(duì)象持有的不同的ActivityBehavior上糊肠。

運(yùn)行流程

創(chuàng)建流程實(shí)例

在demo中通過(guò)RuntimeService發(fā)起流程實(shí)例:

processEngine.getRuntimeService().startProcessInstanceByKey("hello");

在startProcessInstanceByKey方法中執(zhí)行StartProcessInstanceCmd命令:

public class StartProcessInstanceCmd<T> implements Command<ProcessInstance>, Serializable {
    ...
    public ProcessInstance execute(CommandContext commandContext) {
        //獲取流程定義
        ProcessDefinitionEntity processDefinition = ...
        //創(chuàng)建流程實(shí)例
        ExecutionEntity processInstance = processDefinition.createProcessInstance(businessKey);
        //開(kāi)始流程
        processInstance.start();
        return processInstance;
    }
    ...
}

在StartProcessInstanceCmd方中通過(guò)流程定義ProcessDefinitionEntity創(chuàng)建了流程實(shí)例ExecutionEntity:

ExecutionEntity

ExecutionEntity實(shí)現(xiàn)了一些重要接口:

  • PVM相關(guān)的接口辨宠,賦予了ExecutionEntity流程驅(qū)動(dòng)的能力,例如single货裹、start方法嗤形。
  • 實(shí)現(xiàn)VariableScope接口讓ExecutionEntity可以持久上下文變量。
  • ProcessInstance接口暴露了ExecutionEntity關(guān)聯(lián)的ProcessDefinitionEntity的信息弧圆。
  • PersistentObject接口代表ExecutionEntity對(duì)象是需要持久化赋兵。

在ExecutionEntity中維護(hù)類(lèi)一個(gè)屬性:activity。activity屬性代表當(dāng)前執(zhí)行到哪個(gè)節(jié)點(diǎn)搔预,在創(chuàng)建ExecutionEntity過(guò)程中會(huì)設(shè)置activity霹期,使流程從某一個(gè)節(jié)點(diǎn)開(kāi)始,默認(rèn)是開(kāi)始節(jié)點(diǎn)拯田。

最后StartProcessInstanceCmd還調(diào)用ExecutionEntity的start方法開(kāi)始驅(qū)動(dòng)流程:

public void start() {
    performOperation(AtomicOperation.PROCESS_START);
}

驅(qū)動(dòng)流程

Activiti框架的流程運(yùn)行于PVM模型之上历造,在流程運(yùn)行時(shí)主要涉及到PVM中幾個(gè)對(duì)象:ActivityImpl、TransitionImpl和ActivityBehavior船庇。

  • ActivityImpl:ActivityImpl是流程節(jié)點(diǎn)的抽象吭产,ActivityImpl維護(hù)流程圖中節(jié)點(diǎn)的連線,包括有哪些進(jìn)線鸭轮,有哪些出線垮刹。另外還包含節(jié)點(diǎn)同步/異步執(zhí)行等信息。
  • TransitionImpl:TransitionImpl包含source和target兩個(gè)屬性张弛,連接了兩個(gè)流程節(jié)點(diǎn)荒典。
  • ActivityBehavior:每一個(gè)ActivityImpl對(duì)象都擁有一個(gè)ActivityBehavior對(duì)象酪劫,ActivityBehavior代表節(jié)點(diǎn)的行為。

ActivityImpl寺董、TransitionImpl和ActivityBehavior只是描述了流程的節(jié)點(diǎn)覆糟、遷移線和節(jié)點(diǎn)行為,真正要讓ExecutionEntity流轉(zhuǎn)起來(lái)遮咖,還需要AtomicOperation的驅(qū)動(dòng):

AtomicOperation PROCESS_START = new AtomicOperationProcessStart();
AtomicOperation PROCESS_START_INITIAL = new AtomicOperationProcessStartInitial();
AtomicOperation PROCESS_END = new AtomicOperationProcessEnd();
AtomicOperation ACTIVITY_START = new AtomicOperationActivityStart();
AtomicOperation ACTIVITY_EXECUTE = new AtomicOperationActivityExecute();
AtomicOperation ACTIVITY_END = new AtomicOperationActivityEnd();
AtomicOperation TRANSITION_NOTIFY_LISTENER_END = new AtomicOperationTransitionNotifyListenerEnd();
AtomicOperation TRANSITION_DESTROY_SCOPE = new AtomicOperationTransitionDestroyScope();
AtomicOperation TRANSITION_NOTIFY_LISTENER_TAKE = new AtomicOperationTransitionNotifyListenerTake();
AtomicOperation TRANSITION_CREATE_SCOPE = new AtomicOperationTransitionCreateScope();
AtomicOperation TRANSITION_NOTIFY_LISTENER_START = new AtomicOperationTransitionNotifyListenerStart();
    
AtomicOperation DELETE_CASCADE = new AtomicOperationDeleteCascade();
AtomicOperation DELETE_CASCADE_FIRE_ACTIVITY_END = new AtomicOperationDeleteCascadeFireActivityEnd();

在ExecutionEntity的start方法中滩字,調(diào)用了PROCESS_START,PROCESS_START做了幾件事:

  • 獲取流程定義級(jí)別定義的監(jiān)聽(tīng)start事件的ExecutionListener御吞,調(diào)用notify方法麦箍。
  • 如果開(kāi)啟了事件功能,發(fā)布ActivitiEntityWithVariablesEvent和ActivitiProcessStartedEvent陶珠。
  • 調(diào)用PROCESS_START_INITIAL挟裂。

PROCESS_START_INITIAL也實(shí)現(xiàn)了類(lèi)似的功能:

  • 獲取初始節(jié)點(diǎn)上定義的監(jiān)聽(tīng)start事件的ExecutionListener,調(diào)用notify方法揍诽。
  • 調(diào)用ACTIVITY_EXECUTE诀蓉。

在Demo流程執(zhí)行中涉及的AtomicOperation的鏈路主要包括:

  • ACTIVITY_EXECUTE:調(diào)用當(dāng)前activity的behavior。
  • TRANSITION_NOTIFY_LISTENER_END:某個(gè)activity節(jié)點(diǎn)執(zhí)行完畢暑脆,調(diào)用節(jié)點(diǎn)上聲明的監(jiān)聽(tīng)end事件的ExecutionListener渠啤。
  • TRANSITION_NOTIFY_LISTENER_TAKE:觸發(fā)線上的ExecutionListener。
  • TRANSITION_NOTIFY_LISTENER_START:某個(gè)activity節(jié)點(diǎn)即將開(kāi)始執(zhí)行添吗,調(diào)用節(jié)點(diǎn)上的監(jiān)聽(tīng)start事件的ExecutionListener沥曹。

以Demo流程中的ServiceTask節(jié)點(diǎn)helloworld為例,在執(zhí)行ACTIVITY_EXECUTE時(shí)碟联,會(huì)獲取activity關(guān)聯(lián)的behavior:

public class AtomicOperationActivityExecute implements AtomicOperation {
    public void execute(InterpretableExecution execution) {
        ...
        ActivityImpl activity = (ActivityImpl) execution.getActivity();
        ActivityBehavior activityBehavior = activity.getActivityBehavior();
        activityBehavior.execute(execution);
        ...
    }
}

ServiceTask解析時(shí)關(guān)聯(lián)的是ServiceTaskJavaDelegateActivityBehavior妓美,execution方法:

public void execute(ActivityExecution execution) throws Exception {
    //execution中調(diào)用了me.likeyao.activiti.demo.HelloWorld
    execute((DelegateExecution) execution);
    //離開(kāi)當(dāng)前節(jié)點(diǎn)
    leave(execution);
}

在leave方法中調(diào)用了:

bpmnActivityBehavior.performDefaultOutgoingBehavior(execution);

performDefaultOutgoingBehavior方法會(huì)在當(dāng)前activity的
出線中選擇一條,使流程流向下一個(gè)節(jié)點(diǎn)玄帕。在Demo中只有一條線存在:

protected void performOutgoingBehavior(ActivityExecution execution, 
          boolean checkConditions, boolean throwExceptionIfExecutionStuck, List<ActivityExecution> reusableExecutions) {

    if (transitionsToTake.size() == 1) {
        execution.take(transitionsToTake.get(0));
    }         
          
}

最終take方法會(huì)將流程驅(qū)動(dòng)權(quán)交還到AtomicOperation中:

public class ExecutionEntity{
    ...
    public void take(PvmTransition transition, boolean fireActivityCompletionEvent) {
        ...
        setActivity((ActivityImpl)transition.getSource());
        setTransition((TransitionImpl) transition);
        performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_END);
        ...
    }
    ...
}

AtomicOperation的問(wèn)題

按照AtomicOperation的驅(qū)動(dòng)模式部脚,只有當(dāng)遇到UserTask等需要等待single信號(hào)的節(jié)點(diǎn)想邦,調(diào)用才會(huì)返回裤纹。這意味著當(dāng)調(diào)用RuntimeService啟動(dòng)一個(gè)流程實(shí)例時(shí),要一直等到流程運(yùn)行到一個(gè)UserTask節(jié)點(diǎn)調(diào)用才會(huì)返回丧没,如果流程比較長(zhǎng)耗時(shí)非常驗(yàn)證鹰椒。

另一個(gè)問(wèn)題是當(dāng)流程圖比較復(fù)雜,ExecutionListener數(shù)量比較多時(shí)呕童,AtomicOperation之間的互相調(diào)用會(huì)導(dǎo)致調(diào)用棧非常深漆际。

AtomicOperation驅(qū)動(dòng)模式與ExecutionEntity、Behavior等綁定的比較緊密夺饲,暫時(shí)沒(méi)有特別好的辦法替換掉奸汇。

小結(jié)

本文主要介紹了Activiti框架的啟動(dòng)施符、部署、運(yùn)行的主鏈路擂找,并沒(méi)有深入BPMN規(guī)范和Activit功能的具體實(shí)現(xiàn)戳吝,后續(xù)打算根據(jù)Activiti的用戶(hù)手冊(cè),詳細(xì)分析每個(gè)功能的使用和實(shí)現(xiàn)贯涎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末听哭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子塘雳,更是在濱河造成了極大的恐慌陆盘,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件败明,死亡現(xiàn)場(chǎng)離奇詭異隘马,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)肩刃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)祟霍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人盈包,你說(shuō)我怎么就攤上這事沸呐。” “怎么了呢燥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵崭添,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我叛氨,道長(zhǎng)呼渣,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任寞埠,我火速辦了婚禮屁置,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仁连。我一直安慰自己蓝角,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布饭冬。 她就那樣靜靜地躺著使鹅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昌抠。 梳的紋絲不亂的頭發(fā)上患朱,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音炊苫,去河邊找鬼裁厅。 笑死冰沙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的执虹。 我是一名探鬼主播倦淀,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼声畏!你這毒婦竟也來(lái)了撞叽?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤插龄,失蹤者是張志新(化名)和其女友劉穎愿棋,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體均牢,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡糠雨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徘跪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甘邀。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖垮庐,靈堂內(nèi)的尸體忽然破棺而出松邪,到底是詐尸還是另有隱情,我是刑警寧澤哨查,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布逗抑,位于F島的核電站,受9級(jí)特大地震影響寒亥,放射性物質(zhì)發(fā)生泄漏邮府。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一溉奕、第九天 我趴在偏房一處隱蔽的房頂上張望褂傀。 院中可真熱鬧,春花似錦加勤、人聲如沸仙辟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)欺嗤。三九已至参萄,卻和暖如春卫枝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背讹挎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工校赤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吆玖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓马篮,卻偏偏與公主長(zhǎng)得像沾乘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浑测,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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