欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Activiti6.0学习实践(4)-流程引擎配置一

程序员文章站 2024-03-06 10:40:07
...

在上一节,我们进行了一个hello world 的简单应用搭建,本节继续对activiti的一些重要组件进行更进一步的分析。

目录

1、activiti工程骨架

1.2 添加demo类到骨架工程

1.3 创建基于骨架的maven工程

2、流程引擎

2.1 ProcessEngineConifguration:

​​​​​​​2.2 activiti.cfg.xml文件的配置

​​​​​​​3、数据库配置

3.1 支持的数据库

​​​​​​​3.2 数据源配置:

​​​​​​​3.3  数据库更新策略

​​​​​​​3.4 采用默认H2数据库

​​​​​​​3.5 采用mysql数据库

​​​​​​​3.6 采用datasource方式配置

4、日志和数据记录

4.1、activiti的日志组件

​​​​​​​4.2 测试代码

4.3 配置文件

​​​​​​​5、历史记录配置

​​​​​​​5.1、历史记录的使用

​​​​​​​5.2 历史记录的配置


​​​​​​​

1、activiti工程骨架

activiti源码包里面,提供了一份工程骨架,可以将它安装到本地的仓库中

Activiti6.0学习实践(4)-流程引擎配置一

上图中tooling目录下的archetypes目录下就是源码提供的骨架,你可以自己在此基础上进行修改。

1.2 添加demo类到骨架工程

我们把上一节写的demomain.java 放到这里面,注意类的包名是特殊写法,用来创建骨架工程,首先是整体结构如下图:

Activiti6.0学习实践(4)-流程引擎配置一

接着注意DemoMain.java中包名的写法:

Activiti6.0学习实践(4)-流程引擎配置一

下一步要修改打包的骨架元数据,将这里 src/test/java 修改为 src,表示src目录下的所有java类都将被打包进去。修改其他的配置参数的TRUE和false,完成这一步后就可以进行骨架包的打包工作了。

Activiti6.0学习实践(4)-流程引擎配置一

然后,我们进入命令行,进入tooling\archetypes目录,执行 mvn clean install, 这个命令执行成功以后,就把骨架库安装到本地的maven库中。

Activiti6.0学习实践(4)-流程引擎配置一

1.3 创建基于骨架的maven工程

接着我们创建一个maven工程,在选择骨架的时候,要进行添加(将库中的包的GAV id)添加后,就可以创建了。

Activiti6.0学习实践(4)-流程引擎配置一

生成的工程如下所示:

Activiti6.0学习实践(4)-流程引擎配置一

2、流程引擎

流程引擎是actitivi中最重要的组件,作为核心,它的构造过程如下图所示:

Activiti6.0学习实践(4)-流程引擎配置一

​​​​​​​2.1 ProcessEngineConifguration:

查找配置文件并解析activiti.cfg.xml

可以根据不同的场景进行灵活的配置,具体有如下7个创建引擎配置对象的方法

Activiti6.0学习实践(4)-流程引擎配置一

使用(ctrl+H)可以查看下图显示的类的继承图谱

Activiti6.0学习实践(4)-流程引擎配置一

这里重要的类是ProcessEngineConfigurationImpl这个抽象类(名字以impl结尾,但它是一个抽象类),这个类的属性基本上是引擎配置对象最主要的属性

public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfiguration

这个抽象类有4000多行是ProcessEngineConfiguration的主要实现。

在这个抽象类的构造方法中,我们看到默认使用的基于内存H2的数据库,这也是为什么不指定流程引擎的配置文件,我们依然可以正常启动并进行操作的原因。下图中显示了构造函数的部分内容。

Activiti6.0学习实践(4)-流程引擎配置一

​​​​​​​2.2 activiti.cfg.xml文件的配置

下面来看一下activiti.cfg.xml,这个是流程引擎配置对象的配置文件,当然没有这个配置文件也可以启动一个默认配置的对象(前面说了抽象类中默认指定了配置为h2的内存库,解决了启动时的数据库依赖问题)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="databaseType" value="mysql"></property> <!-- 数据库类型,最好配置一下 -->
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti6?characterEncoding=UTF-8"></property>   <!-- 数据库URL,我放在名为activiti数据库中 -->
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>   <!-- 数据库驱动类 mysql是这个,其它的数据库修改一下即可 -->
        <property name="jdbcUsername" value="root"></property>  <!-- 连接数据库的账号 -->
        <property name="jdbcPassword" value="root123"></property>  <!-- 连接数据库的密码 -->
        <property name="databaseSchema" value="activiti"></property>  <!--activiti这个属性可以进行库表创建  true , create-drop -->
        <property name="databaseSchemaUpdate" value="true"></property>
    </bean>

</beans>

这里几个说明:

  1. processEngineConfiguration的实现类有多种实现,可以根据具体的场景进行选用,本例中采用的是StandaloneProcessEngineConfiguration实现。
  2. 数据库jdbcDriver:可以支持多种数据库
  3. databaseSchemaUpdate 配置项,是告诉系统初始情况下,如果没有创建库表,那么会创建系统的库表。

​​​​​​​3、数据库配置

流程引擎默认是使用H2内存数据库,即便什么都不配置,也能正常启动,但是进行的一些修改不能保存下来,重启工程后,修改内容不会保存下来。

数据库配置项目主要有:

基础配置:jdbcUrl,jdbcDriver,jdbcUsername,jdbcPassword,

连接池相关配置:jdbcMaxActiveConnections, jdbcMaxIdleConnections, jdbcMaxCheckoutTime, jdbcMaxWaitTime​​​​​​​

3.1 支持的数据库

支持的数据库种类比较全,有h2, mysql,oracle,postgres,db2, mssql

​​​​​​​3.2 数据源配置:

主要的第三方实现的数据源DataSource:

Druid(阿里),Dbcp(Tomcat自带), HikariCP(光, Spring默认)

Activiti6.0学习实践(4)-流程引擎配置一

​​​​​​​3.3  数据库更新策略

DatabaseSchemaUpdate

False:启动检查数据库版本,发生不匹配抛异常(生产环境时配置)

True:启动检查并更新数据库表,不存在会创建(一般在开发环境配置如此)

Create-drop:启动时创建数据库库表结构,结束时删除(试用于测试)

​​​​​​​3.4 采用默认H2数据库

下面我们采用默认的H2数据库,具体配置如下:

Pom.xml 中添加h2数据库依赖

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.197</version>
    <scope>test</scope>
</dependency>

配置activiti的配置文件 activiti.cfg.xml

<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">

</bean>

我们看一下执行日志

Activiti6.0学习实践(4)-流程引擎配置一

​​​​​​​3.5 采用mysql数据库

下面是采用mysql数据库的配置内容


<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
    <property name="databaseType" value="mysql"></property> <!-- 数据库类型,最好配置一下 -->
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti6?characterEncoding=UTF-8"></property>   <!-- 数据库URL,我放在名为activiti数据库中 -->
    <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>   <!-- 数据库驱动类 mysql是这个,其它的数据库修改一下即可 -->
    <property name="jdbcUsername" value="root"></property>  <!-- 连接数据库的账号 -->
    <property name="jdbcPassword" value="root123"></property>  <!-- 连接数据库的密码 -->
    <property name="databaseSchemaUpdate" value="true"></property>  <!--activiti这个属性可以进行库表创建  true , create-drop -->

</bean>

执行结果

Activiti6.0学习实践(4)-流程引擎配置一

​​​​​​​3.6 采用datasource方式配置

Activiti.cfg.xml 配置内容

<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
    <property name="dataSource" ref="dataSource"></property> <!-- dataSource bean -->
    <property name="databaseSchemaUpdate" value="true"></property>  <!--activiti这个属性可以进行库表创建  true , create-drop -->

</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>   <!-- 数据库驱动类 mysql是这个,其它的数据库修改一下即可 -->
    <property name="url" value="jdbc:mysql://localhost:3306/activiti6?characterEncoding=UTF-8"></property>   <!-- 数据库URL,我放在名为activiti数据库中 -->
    <property name="username" value="root"></property>  <!-- 连接数据库的账号 -->
    <property name="password" value="root123"></property>  <!-- 连接数据库的密码 -->
    <property name="initialSize" value="1"></property>  <!-- -->
    <property name="maxActive" value="20"></property>  <!-- -->
    <property name="filters" value="stat,slf4j"></property>  <!-- -->
</bean>

采用dataSource方式的执行结果

Activiti6.0学习实践(4)-流程引擎配置一

说明:在ProcessEngineConfigurationImpl中有初始化dataSource的过程,如下图所示

​​​​​​​Activiti6.0学习实践(4)-流程引擎配置一

4、日志和数据记录

4.1、activiti的日志组件

常用日志组件可以用如下图表示

Activiti6.0学习实践(4)-流程引擎配置一

在activiti中通常使用slf4j, logbackde 方式。对于日志的配置需要了解一下两点,在logback.xml中配置日志模板%x{mdcProcessInstanceID},引擎的设计是在执行过程中出现异常才会记录MDC(Mapped Diagnostic Contexts)信息。配置流程历史记录级别HistoryLevel有4个级别,不同的级别记录的细节不一样,从低到高分为none,activiti,aduit,full。从aduit开始保存表单属性,同时也说明这个级别开始对性能影响比较显著。下面代码演示了如何开启MDC记录流程日志

​​​​​​​4.2 测试代码

ConfigMDCTest.java

这个类是进行流程操作的测试类,我们期望这个流程执行过程中打印一些流程执行的过程。

import org.activiti.engine.logging.LogMDC;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.test.ActivitiRule;
import org.activiti.engine.test.Deployment;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

/**
 * Describe:
 *
 * @author cwqsolo
 * @date 2020/01/07
 */
public class ConfigMDCTest {

    private static final Logger logger = LoggerFactory.getLogger(ConfigMDCTest.class);

    //这里已经包含了流程引擎的创建
    @Rule
    public ActivitiRule  activitiRule = new ActivitiRule();

    @Test
    @Deployment( resources = {"./my-process.bpmn20.xml"})
    public void configMDCTest1(){

        //LogMDC.setMDCEnabled(true);
        ProcessInstance  processInstance =  activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");;
        assertNotNull(processInstance);

        List<Task> list = activitiRule.getTaskService().createTaskQuery().list();
//        assertEquals("Activiti is awesome!", list.get(0).getName());

        Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
        assertEquals("Activiti is awesome!", task.getName());
        activitiRule.getTaskService().complete( list.get(0).getId() );

    }

}

由于流程引擎设计时只是将错误发生时打印流程信息如id,name,因此在我们需要跟踪流程时打印的信息不够方便,因此需要构造一个拦截器,将拦截器设置到流程中,这样流程运行时,可以通过拦截器打印日志,activiti提供的打印对象为LogMDC。我们实现的拦截器MDCCommandInvoke.java代码如下:


package com.study.activiti.interceptor;

import org.activiti.engine.impl.agenda.AbstractOperation;
import org.activiti.engine.impl.interceptor.DebugCommandInvoker;
import org.activiti.engine.logging.LogMDC;

/**
 * Describe:
 *  设置一个MDC拦截器,可以在非error状态下,就可以打印流程的id等
 * @author cwqsolo
 * @date 2020/01/08
 */
public class MDCCommandInvoke extends DebugCommandInvoker {

    @Override
    public void executeOperation(Runnable runnable) {
        //首先判断一个是否已经设置mdc生效
        boolean mdcEnabled = LogMDC.isMDCEnabled();
        LogMDC.setMDCEnabled(true);
        if( runnable instanceof AbstractOperation){
            AbstractOperation  operation = (AbstractOperation) runnable;
            if( operation.getExecution() != null){
                LogMDC.putMDCExecution( operation.getExecution());
            }
        }

        super.executeOperation(runnable);

        //进行logMDC清理,如果原来已经设置mdc enable,则恢复设置
        LogMDC.clear();
        if(!mdcEnabled){
            LogMDC.setMDCEnabled( false);
        }
    }
}

4.3 配置文件

前面显示的测试代码,要让拦截器工作起来,还需要在配置文件中设定这个拦截器,具体配置文件activiti.cfg.xml的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"></property> <!-- dataSource bean -->
        <property name="databaseSchemaUpdate"
                  value="false"></property>  <!--activiti这个属性可以进行库表创建  true, false , create-drop -->
        <property name="commandInvoker" ref="commandInvoker"/>
    </bean>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName"
                  value="com.mysql.jdbc.Driver"></property>   <!-- 数据库驱动类 mysql是这个,其它的数据库修改一下即可 -->
        <property name="url"
                  value="jdbc:mysql://localhost:3306/activiti6?characterEncoding=UTF-8"></property>   <!-- 数据库URL,我放在名为activiti数据库中 -->
        <property name="username" value="root"></property>  <!-- 连接数据库的账号 -->
        <property name="password" value="root123"></property>  <!-- 连接数据库的密码 -->
        <property name="initialSize" value="1"></property>  <!-- -->
        <property name="maxActive" value="20"></property>  <!-- -->
        <property name="filters" value="stat,slf4j"></property>  <!-- -->
    </bean>

    <!--将我们自定义的流程引擎打印信息用的拦截器设置到流程引擎里面 -->
    <bean id="commandInvoker"  class="com.study.activiti.interceptor.MDCCommandInvoke" />

</beans>

 

​​​​​​​5、历史记录配置

Activiti提供了历史记录配置功能,结合配置文件中的history属性可以进行历史记录的不同详细粒度的查询

​​​​​​​5.1、历史记录的使用

下面的代码展示了如何进行历史记录的查询使用:

ConfigHistoryLevelTest.java 里面已经进行了注释说明如何获取历史流程对象、历史流程任务、历史流程活动、历史流程详情、历史流程表单。

import com.google.common.collect.Maps;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.logging.LogMDC;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.test.ActivitiRule;
import org.activiti.engine.test.Deployment;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Describe:
 *
 * @author cwqsolo
 * @date 2020/01/08
 */
public class ConfigHistoryLevelTest {
    private static final Logger logger = LoggerFactory.getLogger(ConfigHistoryLevelTest.class);

    //这里已经包含了流程引擎的创建
    @Rule
    public ActivitiRule activitiRule = new ActivitiRule("activiti_his.cfg.xml");

    @Test
    @Deployment( resources = {"./my-process.bpmn20.xml"})
    public  void  test(){

        //定义参数
        HashMap<String, Object> params = Maps.newHashMap();
        params.put("key1","value1");
        params.put("key2", "value2");

        //启动流程
        ProcessInstance processInstance =  activitiRule.getRuntimeService().startProcessInstanceByKey("my-process", params);

        //修改变量方式,从执行对象获取到变量(也就是流程数据),可以对流程数据进行修改
        List<Execution> executions = activitiRule.getRuntimeService().createExecutionQuery()
                .listPage(0, 100);
        logger.info(" ++++++++++输出流程对象+++++++++++");
        for (Execution execution:executions   ) {
            logger.info("execution = {} ", execution);
        }
        logger.info("execution.size ={}", executions.size());
        String id = executions.iterator().next().getId();  //取出id
        activitiRule.getRuntimeService().setVariable( id, "key1", "value1_1");

        //通过表单进行数据的修改
        Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
        Map<String, String> properties=Maps.newHashMap();
        properties.put("fromkey1", "valuef1");
        properties.put("formkey2", "valuef2");
        activitiRule.getFormService().submitTaskFormData( task.getId(), properties);

        //输出历史内容
        //1.输出历史活动
        List<HistoricActivityInstance> historicActivityInstances = activitiRule.getHistoryService()
                .createHistoricActivityInstanceQuery().listPage(0, 100);
        logger.info(" ++++++++++输出流程活动历史+++++++++++");
        for (HistoricActivityInstance historicActivityInstance: historicActivityInstances  ) {
            logger.info("histroricActivityInstance = {}", historicActivityInstance);
        }
        logger.info("historicActivityInstances.size = {}", historicActivityInstances.size());

        //2.输出历史任务
        List<HistoricTaskInstance> historicTaskInstances = activitiRule.getHistoryService()
                .createHistoricTaskInstanceQuery().listPage(0, 100);
        logger.info(" ++++++++++输出流程任务历史+++++++++++");
        for (HistoricTaskInstance historicTaskInstance: historicTaskInstances  ) {
            logger.info("histroricTaskInstance = {}", historicTaskInstance);
        }
        logger.info("historicTasknstances.size = {}", historicTaskInstances.size());

        //输出历史变量
        List<HistoricVariableInstance> historicVariableInstances = activitiRule.getHistoryService()
                .createHistoricVariableInstanceQuery().listPage(0, 100);
        logger.info(" ++++++++++输出流程历史变量+++++++++++");
        for (HistoricVariableInstance historicVariableInstance: historicVariableInstances  ) {
            logger.info("historicVariableInstance = {}", historicVariableInstance);
        }
        logger.info("historicVariableInstances.size = {}", historicVariableInstances.size());



        //3.输出历史表单
        List<HistoricDetail> historicDetailsForms = activitiRule.getHistoryService().createHistoricDetailQuery()
                .formProperties().listPage(0, 100);
        logger.info(" ++++++++++输出流程历史表单+++++++++++");
        for (HistoricDetail historicDetailsForm: historicDetailsForms  ) {
            logger.info("historicDetailsForm = {}",to_String( historicDetailsForm));
        }
        logger.info("historicDetailsForms.size = {}", historicDetailsForms.size());

        //4.输出历史详情
        List<HistoricDetail> historicDetails = activitiRule.getHistoryService().createHistoricDetailQuery()
                .listPage(0, 100);
        logger.info(" ++++++++++输出流程历史详情+++++++++++");
        for (HistoricDetail historicDetail: historicDetails ) {
            logger.info("historicDetailsForm = {}", to_String(historicDetail));
        }
        logger.info("historicDetailsForms.size = {}", historicDetails.size());

    }

    /**
     * 使用对象转换为字符串的方法,使得对象里面的数据看起来更清晰
     */
    static String to_String(HistoricDetail  historicDetail){
        return ToStringBuilder.reflectionToString(historicDetail, ToStringStyle.SHORT_PREFIX_STYLE);
    }



}

 

​​​​​​​5.2 历史记录的配置

要让上面的代码发挥作用,还需要配置文件中对history属性进行配置。

Activiti6.0学习实践(4)-流程引擎配置一

历史记录的详细程度从低到高位none,activity,audit,full。下面是使用了full进行配置的结果

Activiti6.0学习实践(4)-流程引擎配置一

只有设置为full才能使得日志可以查看到具体的变量的变化过程。