工作流Activit介绍与应用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
工作流Activiti介绍与应用
工作流(workflow)就是工作流程的计算模型,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计算。
我的理解就是:将部分或者全部的工作流程、逻辑让计算机帮你来处理,实现自动化。
1Activiti简介
Activiti是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理,工作流,服务协作等领域的一个开源,灵活的,易扩展的可执行流程语言框架。
它实现了BPMN 规范,可以发布设计好的流程定义,并通过api进行流程调度。
1.1Activiti基础编程框架
Activiti的基础编程框架如下:
Activiti基于Spring,ibatis等开源中间件作为软件平台,在此之上构建了非常清晰的开发框架。
上图列出了Activiti的核心组件。
:流程引擎的抽象,对于开发者来说,它是我们使用Activiti的外观(faade),通过它可以获得我们需要的一切服务。
(TaskService,RuntimeService,RepositoryService...):Activiti按照流程的生命周期(定义,部署,运行)把不同阶段的服务封装在不同的Service中,用户可以非常清晰地使用特定阶段的接口。
通过ProcessEngine能够获得这些Service实例。
1.2Activiti重要服务类
ProcessEngine:流程引擎的抽象,通过它我们可以获得我们需要的一切服务。
RepositoryService: Activiti中每一个不同版本的业务流程的定义都需要使用一些定义文件,部署文件和支持数据(例如 XML文件,表单定义文件,流程定义图像文件等),这些文件都存储在Activiti内建的Repository中。
RepositoryService提供了对 repository 的存取服务。
TaskService:在Activiti业务流程定义中每一个执行节点都被称作一个Task,流程运行过程中,与每个任务节点相关的接口,比如complete, delete,delegate等等都是TaskService提供的。
IdentityService: Activiti中内置了用户以及组管理的功能,必须使用这些用户和组的信息才能获取到相应的Task。
IdentityService提供了对Activiti 系统中的用户和组的管理功能。
FormService:Activiti中的流程和Task状态均可关联业务相关的数据。
通过FormService 可以存取启动和完成任务所需要的表单数据。
RuntimeService:在Activiti中,每当一个流程定义被启动一次之后,都会生成一个相应的流程对象实例。
RuntimeService提供了启动流程、查询流程实例、设置获取流程实例变量等功能。
此外它还提供了对流程部署,流程定义和流程实例的存取服务。
. ManagementService: ManagementService提供了对Activiti流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于Activiti系统的日常维护。
HistoryService: HistoryService用于获取正在运行或已经完成的流程实例的信息,与RuntimeService中获取的流程信息不同,历史信息包含已经持久化存储的永久信息,并已经被针对查询优化。
关于ProcessEngine和XXService的关系,可以看下面这张图:
2Activiti深入
2.1Activiti配置类分析
ProcessEngineConfiguration类的结构图如下图:
正如上图所示,ProcessEngineConfiguration是全部配置类的父类,有一个ProcessEngineConfigurationImpl子类,ProcessEngineConfigurationImpl下面有三个直接的子类,其中ProcessEngineConfiguration和ProcessEngineConfigurationImpl都是抽象类。
这个类是我们编程时第一个使用的类,有了这个类的层级结构,我们就比较容易理解通过该类获取各种具体实现的ProcessEngineConfiguration类的实例了。
();
("");
();
通过上面的方法,可以获取流程引擎的配置类的实例,这些实例有的是通过配置文件进行配置的,有的则是通过程序的方法进行指定,比如:
();
生成这样的配置实例后,需要对该实例进行数据库连接相关的配置等等。
2.2 Activiti命令执行器分析
ACTIVITI 所有执行过程都是采用命令模式,使用命令执行器进行执行,这个可是从RuntimeServiceImpl启动流程的代码可以看出来:
public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey) {
return (new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, null));
}
为了了解命令执行commandExecutor,特分如下几节来说明它的构造,传递,以及命令执行执行的过车过你。
2.2.1命令执行器的构造
命令执行器是一个采用拦截器链式的结构,这个可以从如下的分析得出:commandExecutor对象是首先在ProcessEngineConfigurationImpl的初始化方法中产生:protected void initCommandExecutor() {
if (commandExecutor==null) {
CommandInterceptor first = initInterceptorChain(commandInterceptors);
commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
}
}
而这个命令执行器commandExecutor的构造过程中跟commandInterceptors中的第一个命令
拦截器有关,而commandInterceptors是命令拦截器的列表。
protected void initCommandInterceptors() {
if (commandInterceptors==null) {
commandInterceptors = new ArrayList<CommandInterceptor>();
if (customPreCommandInterceptors!=null) {
(customPreCommandInterceptors);
}
(getDefaultCommandInterceptors());
if (customPostCommandInterceptors!=null) {
(customPostCommandInterceptors);
}
(commandInvoker);
}
}
protected Collection< extends CommandInterceptor> getDefaultCommandInterceptors() {
List<CommandInterceptor> interceptors= new ArrayList<CommandInterceptor>();
(new LogInterceptor());
CommandInterceptor transactionInterceptor = createTransactionInterceptor();
if (transactionInterceptor != null) {
(transactionInterceptor);
}
(new CommandContextInterceptor(commandContextFactory, this));
return interceptors;
}
同时每个拦截器又是通过next域的方式将不同的拦截器进行链接形成一个链接结构,这个可以从initInterceptorChain方法可以看出来:
protected CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {
if (chain==null || ()) {
throw new ActivitiException("invalid command interceptor chain configuration: "+chain);
}
for (int i = 0; i < ()-1; i++) {
(i).setNext( (i+1) );
}
return (0);
}
2.2.2命令执行器的传递
命令执行器commandExecutor对象在ProcessEngineConfigurationImpl的初始化方法中生成,那么为什么它会在RuntimeService等service对象中获取呢
依然回到ProcessEngineConfigurationImpl初始化过程,初始化过程会调用initServices方法,将runtimeService等Service实例与该命令执行体commandExecutor 进行绑定。
protected void initServices() {
initService(repositoryService);
initService(runtimeService);
initService(historyService);
initService(identityService);
initService(taskService);
initService(formService);
initService(managementService);
initService(dynamicBpmnService);
}
protected void initService(Object service) {
if (service instanceof ServiceImpl) {
((ServiceImpl)service).setCommandExecutor(commandExecutor);
}
} protected void initService(Object service) {
if (service instanceof ServiceImpl) {
((ServiceImpl)service).setCommandExecutor(commandExecutor);
}
}
2.2.3命令执行器执行命令过程
这个可以从CommandExecutor的具体实现类CommandExecutorImpl的execute方法进行分析:
public <T> T execute(Command<T> command) {
return execute(defaultConfig, command);
public <T> T execute(CommandConfig config, Command<T> command) { return (config, command);
}
从中可以看出其实是将命令的处理交给命令拦截器first去处理
其中这个first就是LogInterceptor对象的引用,它执行的逻辑如下:public <T> T execute(CommandConfig config, Command<T> command) { if (!()) {
etSimpleName());
try {
return (config, command);
} finally {
("--- {} finished
--------------------------------------------------------",
().getSimpleName());
("\n");
}
CommandContextInterceptor顾名思义,它是一个拦截器,拦截所有命令,在命令执行前后执行一些公共性操作。
比如CommandContextInterceptor的核心方法:
Java代码
1.public<T>Texecute(Command<T>command){
mandContextcontext=(command);
3.try{
reateDeployment()
.addClasspathResource("diagrams/") .addClasspathResource("diagrams/") .deploy();
"deploy ID:"+());
"deploy Name:"+());
}
启动完成后在act_re_deployment、act_re_procdef、act_ge_bytearray表中会有对应的数据信息。
2.3启动流程实例
/**
* 启动流程实例
*/
@Test
public void startFlow(){
RuntimeService runtimeService=();
ProcessInstance processInstance=("myProcess");
"processInstance ID:"+());
"ProcessDefinitionId ID:"+());
RepositoryService repositoryService=();
ProcessDefinition def=());
"processDefinition ID:"+());
"processDefinition key:"+());
try {
(5000);
} catch (InterruptedException e) {
();
}
}
启动完流程后数据库发生的变化:
1、取出act_ge_property表的name=的那条记录的value值作为启动流程实例唯一的ID;
2、在act_ru_execution表中会产生一条数据,这条数据记录了当前流程正在执行的任务,其中act_id_字段的值对应流程图节点的ID值。
(org\activiti\db\mapping\entity\ insertExecution)
3、在act_hi_procinst表中会产生一条数据,记录当前流程的历史信息。
(org\activiti\db\mapping\entity\ insertHistoricProcessInstance)
4、在act_hi_actinst表中会产生多条数据,记录当前流程执行完成的节点和等待执行节点的历史信息。
(org\activiti\db\mapping\entity\
insertHistoricActivityInstance)
5、在act_ru_variable表中会产生多条数据,以记录当前流程的变量信息;
(org\activiti\db\mapping\entity\
insertVariableInstance)
6、在act_hi_varinst表中会产生多条数据,以记录当前流程的历史变量信息。
7、在act_ru_task表中会产生一条任务数据,execution_id_对应act_ru_execution 主键,proc_inst_id_为流程实例ID,name_值为流程节点名称,assignee_字段为该待办当前的处理。
(org\activiti\db\mapping\entity\
insertTask)
8、在act_hi_taskinst表中插入用户任务执行的情况
(org\activiti\db\mapping\entity\
insertHistoricTaskInstance)
2.4查询待办任务并提交任务
/**
*查询待办任务并提交任务
*/
@Test
public void queryTaskAndComplete(){
String assignee="张三";
TaskService taskService = ();
List<Task> taskList=()
.taskAssignee(assignee)
.list();
if(taskList!=null){
for(Task task:taskList){
"代办任务ID:"+());
"代办任务名称:"+());
"任务创建时间:"+());
"所属的流程ID:"+());
"执行对象ID:"+());
"流程定义ID:"+());
Map<String,Object> variables = new HashMap<String,Object>();
("申请理由", "理由123");
(), variables);
}
}
}
其中taskId对应act_ru_task表的主键ID,因为当前待办任务为第一个节点提交申请,当执行完这个待办后下一条待办数据将会流转到审批【部门经理】那,然后以此类推可以将部门经理和总经理的待办任务全部查询和执行完成。
2.5查询和删除流程定义
/**
* 查询流程定义
*/
@Test
public void queryProcessDefinition(){
RepositoryService repositoryService=();
List<ProcessDefinition> list=()
.orderByProcessDefinitionVersion()
eploymentId(deploymentId)
rocessDefinitionId(processDefinitionId)
rocessDefinitionKey(processDefinitionKey) rocessDefinitionCategoryLike(processDefinitionCategoryLike) .asc()
ingleResult()
.list();
if(list!=null){
for(ProcessDefinition def:list){
"流程定义ID:"+());
"流程定义名称:"+());
"流程定义key:"+());
"流程定义版本:"+());
"资源名称bpmn文件:"+());
"资源名称png文件:"+());
"部署ID:"+());
}
}
}
/**
* 删除流程定义
*/
@Test
public void delProcessDefinition(){
RepositoryService repositoryService=();
("1",true);indExecutionById(executionId);
}
Map<String, JobHandler> jobHandlers = ().getJobHandlers();
JobHandler jobHandler = (jobHandlerType);
(this, jobHandlerConfiguration, execution, commandContext);
}
timer-intermediate-transition= timer-transition= suspend-processdefinition= async-continuation= timer-start-event= void execute(JobEntity job, String
configuration, ExecutionEntity execution, CommandContext commandContext) {
etOutgoingTransitions();
();
lockConcurrentRoot(execution);
List<ActivityExecution> joinedExecutions = (activity);
int nbrOfExecutionsToJoin = ().getIncomingTransitions().size();
int nbrOfExecutionsJoined = ();
().getHistoryManager().recordActivityEnd((ExecutionEntity) execution);
if (nbrOfExecutionsJoined==nbrOfExecutionsToJoin) {
// Fork
if()) {
("parallel gateway '{}' activates: {} of {} joined", (), nbrOfExecutionsJoined, nbrOfExecutionsToJoin);
}
(outgoingTransitions, joinedExecutions);
} else if ()){
("parallel gateway '{}' does not activate: {} of {} joined", (),
nbrOfExecutionsJoined, nbrOfExecutionsToJoin); }
}。