Activiti6.0引擎配置

872 阅读7分钟

概述

Activiti流程引擎配置

image-20210206144251032.png

流程引擎配置类的作用

ProcessEngineConfiguration

  • 查找并解析xml配置文件activiti.cfg.xml
  • 提供多个静态方法创建配置对象
  • 实现几个基于不同场景的子类,配置方式灵活

activiti.cfg.xml

image-20210210152628811.png

静态方法创建配置对象

image-20210210155036332.png

多个子类适配不同场景

image-20210210155503943.png

ProcessEngineConfiguration 类

  • ProcessEngineConfigurationImpl 它不是一个实现类是一个抽象类,配置ProcessEngineConfiguration百分之80的属性和一些get,set方法
  • StandloneProcessEngineConfiguration 根据new的方式创建对象,使用java代码调用策略方法
  • SpringProcessEngineConfiguration 基于Spring的集成Spring对它的功能扩展数据源扩展,事物扩展定一个了一个事物可以装载的目录

创建流程引擎配置-archetype

创建脚手架

  • 工程目录位置 Activiti-boot2/tooling/activiti-archetype-unittest

擎配置-config_samples

image-20210210193413884.png

创建流程引擎配置-config_samples

createProcessEngineConfigurationFromResourceDefault

  • 代码如下
public class ConfigTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigTest.class);

    @Test
    public void testConfig1() {
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResourceDefault();

        LOGGER.info("configuration = {}", configuration);
    }
}
  • 日志打印结果如下

    09:58:22.914[main][INFO ]Loading XML bean definitions from class path resource [activiti.cfg.xml]  ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= o.s.b.f.x.XmlBeanDefinitionReader.loadBeanDefinitions:316
    
    
    09:58:23.682[main][INFO ]configuration = org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration@279fedbd  ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= c.ConfigTest.testConfig1:21
    

    日志分析如下

image-20210211101517109.png

createStandaloneInMemProcessEngineConfiguration

代码如下

    @Test
    public void testConfig2() {
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration
                .createStandaloneInMemProcessEngineConfiguration();
        LOGGER.info("configuration = {}", configuration);
    }

打印日志如下

10:15:47.331[main][INFO ]configuration = org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration@78e94dcf  ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= c.ConfigTest.testConfig2:28

日志分析如下

image-20210211101751107.png

源码分析

createStandaloneInMemProcessEngineConfiguration

ProcessEngineConfiguration
        .createStandaloneInMemProcessEngineConfiguration()
  • 底层源码分析得到

  • 实质上调用了h2数据库

  • 不依赖Spring

    public class StandaloneInMemProcessEngineConfiguration extends StandaloneProcessEngineConfiguration {
        public StandaloneInMemProcessEngineConfiguration() {
            this.databaseSchemaUpdate = "create-drop";
            this.jdbcUrl = "jdbc:h2:mem:activiti";
        }
    }
    

createProcessEngineConfigurationFromResourceDefault

  • 点击进入下一层源码

    public static ProcessEngineConfiguration createProcessEngineConfigurationFromResourceDefault() {
            return createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration");
        }
    

image-20210211103340362.png

  • 获取classPath下的resource文件

    public static ProcessEngineConfiguration parseProcessEngineConfigurationFromResource(String resource, String beanName) {
            Resource springResource = new ClassPathResource(resource);
            return parseProcessEngineConfiguration(springResource, beanName);
        }
    

image-20210211103525007.png

  • 和SpringBean文件一起组装一起

    public static ProcessEngineConfiguration parseProcessEngineConfiguration(Resource springResource, String beanName) {
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
            xmlBeanDefinitionReader.setValidationMode(3);
            xmlBeanDefinitionReader.loadBeanDefinitions(springResource);
            ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl)beanFactory.getBean(beanName);
            processEngineConfiguration.setBeans(new SpringBeanFactoryProxyMap(beanFactory));
            return processEngineConfiguration;
        }
    

image-20210211103804027.png

ProcessEngineConfiguration 源码分析

ProcessEngineConfigurationImp是继承ProcessEngineConfiguration类

  // false 是不会对数据库做修改的 
  public static final String DB_SCHEMA_UPDATE_FALSE = "false";
  // 启动时候创建销毁的时候销毁
  public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";
  public static final String DB_SCHEMA_UPDATE_TRUE = "true";
  public static final String NO_TENANT_ID = "";
  protected String processEngineName = "default";

  // 集成邮件的配置
  protected String mailServerHost;
  protected String mailServerUsername;
  protected String mailServerPassword;

  // 默认是使用的H2数据库,生产环境默认不推荐使用
  this.databaseSchemaUpdate = "false";
  this.jdbcDriver = "org.h2.Driver";
  this.jdbcUrl = "jdbc:h2:tcp://localhost/~/activiti";

  // 生成流程图设置字体
   this.xmlEncoding = "UTF-8";
   this.defaultCamelContext = "camelContext";
   this.activityFontName = "Arial";
   this.labelFontName = "Arial";
   this.annotationFontName = "Arial";

  // 对流程图渲染生成渲染的工具
  public ProcessDiagramGenerator getProcessDiagramGenerator() {
      return this.processDiagramGenerator;
  }

 // 对数据库表名生成做配置
 this.databaseTablePrefix = "";

最重要的方法

  @Override
  public ProcessEngine buildProcessEngine() {
    init();
    ProcessEngineImpl processEngine = new ProcessEngineImpl(this);

    // trigger build of Activiti 5 Engine
    if (isActiviti5CompatibilityEnabled && activiti5CompatibilityHandler != null) {
      Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
      activiti5CompatibilityHandler.getRawProcessEngine();
    }

    postProcessEngineInitialisation();

    return processEngine;
  }
  • init()

    public void init() {
        initConfigurators();
        configuratorsBeforeInit();
        initProcessDiagramGenerator();
        initHistoryLevel();
        initExpressionManager();
    
        if (usingRelationalDatabase) {
          initDataSource();
        }
    
        initAgendaFactory();
        initHelpers();
        initVariableTypes();
        initBeans();
        initFormEngines();
        initFormTypes();
        initScriptingEngines();
        initClock();
        initBusinessCalendarManager();
        initCommandContextFactory();
        initTransactionContextFactory();
        initCommandExecutors();
        initServices();
        initIdGenerator();
        initBehaviorFactory();
        initListenerFactory();
        initBpmnParser();
        initProcessDefinitionCache();
        initProcessDefinitionInfoCache();
        initKnowledgeBaseCache();
        initJobHandlers();
        initJobManager();
        initAsyncExecutor();
    
        initTransactionFactory();
    
        if (usingRelationalDatabase) {
          initSqlSessionFactory();
        }
    
        initSessionFactories();
        initDataManagers();
        initEntityManagers();
        initHistoryManager();
        initJpa();
        initDeployers();
        initDelegateInterceptor();
        initEventHandlers();
        initFailedJobCommandFactory();
        initEventDispatcher();
        initProcessValidator();
        initDatabaseEventLogging();
        initActiviti5CompatibilityHandler();
        configuratorsAfterInit();
      }
    

SpringProcessEngineConfiguration

image-20210211112902386.png

数据库配置-dbconfig

数据库配置

  • 确实默认配置,使用H2内存数据库

  • 配置JDBC属性,使用Mybatis提供的连接池

  • 配置DataSource,可自选第三方实现

  • 配置JDBC属性使用mybatis提供的连接池

image-20210211122747433.png

数据原配置

  • 配置第三方实现的DataSource

image-20210211122841318.png

  • Druid 数据源连接池

image-20210211123002027.png

image-20210211123206211.png

支持的数据库类型

  • 配置databaseType

image-20210211123257492.png

数据库更新策略

  • 配置dataSourceSchemaUpdate

image-20210211123838721.png

数据库配置-dbconfig_code

使用默认数据创建数据源

  • Java代码
public class ConfigDBTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigDBTests.class);

    @Test
    public void testConfig1() {
        ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
        LOGGER.info("cfg = {}", cfg);
        ProcessEngine processEngine = cfg.buildProcessEngine(); // 创建引擎
        LOGGER.info("获取流程引擎 {}", processEngine.getName());
        processEngine.close();
    }
}

image-20210211142715785.png

  • 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="jdbcUrl"
                      value="jdbc:mysql://localhost:3306/activiti6unit?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
            <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUsername" value="root"/>
            <property name="jdbcPassword" value="root123456"/>
            <property name="databaseSchemaUpdate" value="create-drop"/> <!--避免忽略把这个加上-->
            <!--        <property name="databaseSchemaUpdate" value="true"/>--><!--这样配置就算数据库里面有表也会执行过去,但是单元测试遗留的脏数据会遗留在库里面-->
        </bean>
    
    </beans>
    
    

使用DataSource数据源的方式

  • 使用Druid数据源
  • JavaTest代码
    @Test
    public void testConfig2() {
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti_druid.cfg.xml");
        LOGGER.info("processEngineConfiguration = {}", processEngineConfiguration);
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        LOGGER.info("获取流程引擎 = {}", processEngine.getName());
        processEngine.close();
    }
  • activiti_druid.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="databaseSchemaUpdate" value="true"/>
            <property name="dataSource" ref="dataSource"/>
            <property name="dbHistoryUsed" value="true"/>
            <property name="dbIdentityUsed" value="true"/>
            <property name="databaseTablePrefix" value="t_"/>
            <property name="databaseType" value="mysql"/>
        </bean>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url"
                      value="jdbc:mysql://localhost:3306/activiti6unit?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="username" value="root"/>
            <property name="password" value="root123456"/>
            <property name="initialSize" value="1"/>
            <property name="maxActive" value="10"/>
            <property name="filters" value="stat,sl4j"/>
      </bean>
    </beans>
    
    

日志记录配置-logging

日志组件的关系级MDC

日志组件

image-20210211161848232.png

日志记录与MDC

配置开启MDC(Mapped Diagnostic Contexts)
  • 默认没有开启,需要手动设置LogMDC.setMDCEnable(true)
  • 配置logback.xml日志模板%X{mdcProcessInstanceID}
  • 流程只有在执行的过程中出现异常时才会记录MDC信息
配置HistoryLevel
  • none:不记录历史流程,性能高,流程结束后不可读取
  • activiti:归档流程实例和活动实例,流程变量不同步
  • audit: 默认值,在acitviti基础上同步变量值,保存单表属性
  • full:性能比较差,记录所有实例和变量细节变化

配置基于DB的事件日志

配置Event Logging
  • 实验性的事件记录机制,性能影响较大
  • 开启默认记录所有数据的变化过程,表记录快速增长
  • 日志内容JSON格式,建议使用mogoDB,Elastic Search

日志记录配置-logging_mdc

java配置测试类

public class ConfigMDCTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigMDCTests.class);

    @Rule
    public ActivitiRule activitiRule = new ActivitiRule();

    @Test
    @Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"})
    public void test() {
        LogMDC.setMDCEnabled(true);
        ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
        assertNotNull(processInstance);

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


}

my-process.bpmn20.xml

<?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: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="my-process">

        <startEvent id="start"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>

        <!--		<userTask id="someTask" name="Activiti is awesome!" />-->
        <serviceTask id="someTask" activiti:class="com.imooc.activiti.delegage.MDCErrorDelegage"/>
        <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>

        <endEvent id="end"/>

    </process>

</definitions>

测试异常类

public class MDCErrorDelegage implements JavaDelegate {
    private static final Logger LOGGER = LoggerFactory.getLogger(MDCErrorDelegage.class);


    @Override
    public void execute(DelegateExecution execution) {
        LOGGER.info("run MDCErrorDelegage");
        throw new RuntimeException("only test");
    }
}

历史记录配置-history-1

Java代码,xml代码如下

  • ConfigHistoryLevelTests
public class ConfigHistoryLevelTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigHistoryLevelTests.class);

    @Rule
    public ActivitiRule activitiRule = new ActivitiRule("activiti_history.cfg.xml");

    @Test
    @Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"})
    public void test() {
        // 启动流程
        startProcessInstance();

        // 修改变量
        changeVariable();

        // 提交表单 task
        submitTaskFormData();

        // 输出历史内容
        // 输出历史活动
        showHistoryActivity();

        // 输出历史变量
        showHistoryVariable();

        // 输出历史用户任务
        showHistoryTask();

        // 输出历史表单
        showHistoryForm();

        // 输出历史详情
        showHistoricDetails();

    }

    private void showHistoricDetails() {
        List<HistoricDetail> historicDetails = activitiRule.getHistoryService()
                .createHistoricDetailQuery().listPage(0, 100);
        for (HistoricDetail historicDetail : historicDetails) {
            LOGGER.info("historicDetail = {}", toString(historicDetail));
        }
        LOGGER.info("historicDetail.size() = {}", historicDetails.size());
    }

    private void showHistoryForm() {
        List<HistoricDetail> historicDetailForm = activitiRule.getHistoryService()
                .createHistoricDetailQuery().listPage(0, 100);
        for (HistoricDetail historicDetail : historicDetailForm) {
            LOGGER.info("historicDetail = {}", toString(historicDetail));
        }
        LOGGER.info("historicDetailForm.size = {}", historicDetailForm.size());
    }

    private void showHistoryTask() {
        List<HistoricTaskInstance> historicTaskInstances = activitiRule.getHistoryService()
                .createHistoricTaskInstanceQuery().listPage(0, 100);
        for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
            LOGGER.info("historicTaskInstance = {}", historicTaskInstance);
        }
        LOGGER.info("historicTaskInstance.size = {}", historicTaskInstances.size());
    }

    private void showHistoryVariable() {
        List<HistoricVariableInstance> historicVariableInstances = activitiRule.getHistoryService()
                .createHistoricVariableInstanceQuery()
                .listPage(0, 100);
        for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
            LOGGER.info("historicVariableInstance = {}", historicVariableInstance);
        }
        LOGGER.info("historicVariableInstance.size() = {}", historicVariableInstances.size());
    }

    private void showHistoryActivity() {
        List<HistoricActivityInstance> historicActivityInstances = activitiRule.getHistoryService()
                .createHistoricActivityInstanceQuery().listPage(0, 100);
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            LOGGER.info("historicActivityInstance {} =", historicActivityInstance);
        }
        LOGGER.info("historicActivityInstance.size = {}", historicActivityInstances.size());
    }

    private void submitTaskFormData() {
        Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
        HashMap<String, String> properties = Maps.newHashMap();
        properties.put("formkey1", "valuef1");
        properties.put("formkey2", "valuef2");
        activitiRule.getFormService().submitStartFormData(task.getId(), properties);
    }

    private void changeVariable() {
        List<Execution> executions = activitiRule.getRuntimeService().createExecutionQuery()
                .listPage(0, 100);
        for (Execution execution : executions) {
            LOGGER.info("execution ={}", execution);
        }
        LOGGER.info("execution.size = {}", executions.size());
        String id = executions.iterator().next().getId();
        activitiRule.getRuntimeService().setVariable(id, "keyStart1", "value1_");
    }

    private void startProcessInstance() {
        HashMap<String, Object> params = Maps.newHashMap();
        params.put("keyStart1", "value1");
        params.put("keyStart2", "value2");
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process");
    }

    static String toString(HistoricDetail historicDetail) {
        return ToStringBuilder.reflectionToString(historicDetail, ToStringStyle.SHORT_PREFIX_STYLE);
    }


}
  • activiti_history.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="commandInvoker" ref="commandInvoker"/>
        <!--<property name="history" value="none"/>-->
        <!--<property name="history" value="activity"/>-->
        <!--<property name="history" value="audit"/>-->
        <property name="history" value="none"/>
      </bean>
      <bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/>
    
    </beans>
    
    
  • 拦截器(MDCComandInvoker)

    public class MDCComandInvoker extends DebugCommandInvoker {
        @Override
        public void executeOperation(Runnable runnable) {
            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.clear();
            if (!mdcEnabled) {
                LogMDC.setMDCEnabled(false);
            }
        }
    }
    
  • 测试结果

image-20210212092408216.png

image-20210212092436817.png

image-20210212092502547.png

事件处理及监听器配置-eventlog

Java代码及xml代码

public class ConfigEventLogTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigEventLogTests.class);

    @Rule
    public ActivitiRule activitiRule = new ActivitiRule("activiti_eventlog.cfg.xml");

    @Test
    @Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"})
    public void test() {
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process");
        Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
        activitiRule.getTaskService().complete(task.getId());
        List<EventLogEntry> eventLogEntries = activitiRule.getManagementService()
                .getEventLogEntriesByProcessInstanceId(processInstance.getProcessInstanceId());
        for (EventLogEntry eventLogEntry : eventLogEntries) {
            LOGGER.info("eventLogEntry.type = {},eventLogEntry.data = {}", eventLogEntry.getType(), eventLogEntry.getData());
        }
        LOGGER.info("eventLogEntries.size = {}", eventLogEntries.size());
    }


}
  • activiti_eventlog.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="commandInvoker" ref="commandInvoker"/>
        <property name="enableDatabaseEventLogging" value="true"/>
    </bean>
    <bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/>

</beans>

事件处理及监听器配置-eventLinstener-1

监听器原理

image-20210212113628561.png

  • 监听器
  • 事件源 :是流程引擎对象
  • 事件类型:创建类型

监听器配置方式

配置Listener

  • eventListener:监听所有事件派发通知
  • typeEventListerners: 监听指定事件类型的通知
  • activiti:eventListener:只监听特定流程事件

Activiti的事件监听

image-20210212114715008.png

相关API

  • ActivitiEvent:事件监听
  • ActivitiEventListener:监听器(所有类的监听抽象接口)
  • ActivitiEventType:事件类型(是一个枚举类型30多个枚举类型)

事件处理及监听器配置-eventLinstener-2

监听器的配置方式

Activiti的事件监听

命令拦截器配置-command-1

命令模式和责任链模式

命令模式

image-20210212123954012.png

image-20210212123800762.png

责任链模式

命令拦截器的配置

image-20210212124026399.png

配置Interceptor
  • customPreCommandInterceptors :配置在默认拦截器之前
  • customPostCommandInterceptors: 配置在默认拦截器之后
  • commandInvoke: 配置最后的拦截器

image-20210212124501785.png

拦截器的配置方式

  • Java代码

    public class ConfigInterceptorTests {
        private static final Logger LOGGER = LoggerFactory.getLogger(ConfigInterceptorTests.class);
    
        @Rule
        public ActivitiRule activitiRule = new ActivitiRule("activiti_intercptor.cfg.xml");
    
        @Test
        @Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"})
        public void test() {
            ProcessInstance processInstance = activitiRule.getRuntimeService()
                    .startProcessInstanceByKey("my-process");
            Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
            activitiRule.getTaskService().complete(task.getId());
        }
    
    
    }
    
  • activiti_intercptor.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="commandInvoker" ref="commandInvoker"/>
            <property name="enableVerboseExecutionTreeLogging" value="false"/><!--记录怎个过程的日志-->
            <property name="enableDatabaseEventLogging" value="false"/>
            <property name="customPreCommandInterceptors">
                <list>
                    <bean class="com.imooc.activiti.interceptor.DurationCommandInterceptor"/>
                </list>
            </property>
        </bean>
    
        <bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/>
    
    </beans>
    
    
  • 执行结果

image-20210212134651873.png

image-20210212134545465.png

image-20210212134604553.png

image-20210212134627680.png

image-20210212134651873.png

作业执行器配置-job-1

作业执行器的配置

  • asyncExecutorActivitate:激活作业执行器
  • asyncExecutorXXX :异步执行器属性配置
  • asyncExecutor: 异步执行器Bean

自定义线程池ExecutorService

  • corePoolSize :核心线程数
  • maxPoolSize: 最大线程数
  • queueCapacity: 阻塞队列大小

image-20210212153119739.png

定时开始事件(Timer Start Event)

  • timeDate:指定启动时间
  • timeDuration:指定持续时间间隔后执行
  • timeCycle:R5/P1DT1H指定事件段后期执行

作业执行器配置-job-2

配置自定义线程池

    <bean id="executorService" class="org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean">
        <property name="threadNamePrefix" value="activiti-job-"/>
        <property name="corePoolSize" value="5"/>
        <property name="maxPoolSize" value="20"/>
        <property name="queueCapacity" value="100"/>
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$AbortPolicy"/>
        </property>
    </bean>
  • activiti_job.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="commandInvoker" ref="commandInvoker"/>-->
        <property name="enableDatabaseEventLogging" value="true"/>
        <!--异步激活器-->
        <property name="asyncExecutorActivate" value="true"/>
        <!--异步执行器-->
        <property name="asyncExecutor" ref="asyncExecutor"/>
        <!--配置事件监听-->
        <property name="eventListeners">
            <list>
                <bean class="com.imooc.activiti.event.JobEventListener"/>
            </list>
        </property>
    </bean>
    <bean id="asyncExecutor" class="org.activiti.engine.impl.asyncexecutor.DefaultAsyncJobExecutor">
        <property name="executorService" ref="executorService"/>
    </bean>
    <bean id="executorService" class="org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean">
        <property name="threadNamePrefix" value="activiti-job-"/>
        <property name="corePoolSize" value="5"/>
        <property name="maxPoolSize" value="20"/>
        <property name="queueCapacity" value="100"/>
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$AbortPolicy"/>
        </property>
    </bean>
    <bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/>

</beans>

  • my-process_job.bpmn20.xml

        <process id="my-process">
    
            <!--        <startEvent id="start"/>-->
            <startEvent id="start">
                <timerEventDefinition>
                    <timeCycle>R5/PT10S</timeCycle><!--间隔10s去执行-->
                </timerEventDefinition>
    
            </startEvent>
            <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>
    
            <!--		<userTask id="someTask" name="Activiti is awesome!" />-->
            <serviceTask id="someTask" activiti:class="com.imooc.activiti.delegage.MDCErrorDelegage"/>
            <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>
    
            <endEvent id="end"/>
            
        </process>
    
  • ConfigJobTest

    public class ConfigJobTests {
        private static final Logger LOGGER = LoggerFactory.getLogger(ConfigJobTests.class);
    
        @Rule
        public ActivitiRule activitiRule = new ActivitiRule("activiti_job.cfg.xml");
    
        @Test
        @Deployment(resources = {"com/imooc/activiti/my-process_job.bpmn20.xml"})
        public void test() throws InterruptedException {
            LOGGER.info("start");
            List<Job> jobList = activitiRule.getManagementService().createTimerJobQuery().listPage(0, 100);
            for (Job job : jobList) {
                LOGGER.info("定时任务 = {},默认重试次数 = {}", job, job.getRetries());
            }
            LOGGER.info("jobList.size() = {}", jobList.size());
            Thread.sleep(1000*1000);
            LOGGER.info("end");
        }
    
    
    }
    
  • JobEventListener

    public class JobEventListener implements ActivitiEventListener {
        private static final Logger LOGGER = LoggerFactory.getLogger(JobEventListener.class);
    
        @Override
        public void onEvent(ActivitiEvent event) {
            ActivitiEventType eventType = event.getType();
            String name = eventType.name();
            if (name.startsWith("TIMER") || name.startsWith("JOB")) {
                LOGGER.info("监听Job事件 {}\t {}", eventType,event.getProcessInstanceId() );
            }
        }
    
        @Override
        public boolean isFailOnException() {
            return false;
        }
    }
    
  • 执行结果

image-20210212170201634.png

image-20210212170212636.png

Activiti与spring集成-1

集成Spring配置

相关配置

  • 添加pom依赖activit-spring
  • 基于Spring的默认配置activiti-content.xml
  • Acitiviti核心服务注入Spring

功能特性

  • 集成Sping事物管理器
  • 定义文件表达式中使用Spring bean
  • 自动部署资源文件

单元测试

  • 添加pom依赖Spring-test
  • 辅助测试Rule:ActivitiRule
  • 辅助测试TestCase:SpringActivitiTestCase (早期Junit3的扩展方式)

基于Spring对Activiti的管理

  • ConfigSpringTests

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:activiti-content.xml"})
    public class ConfigSpringTests {
        private static final Logger LOGGER = LoggerFactory.getLogger(ConfigSpringTests.class);
    
        @Rule
        @Autowired
        public ActivitiRule activitiRule;
    
        @Resource
        private RuntimeService runtimeService;
    
        @Resource
        private TaskService taskService;
    
        @Test
        @Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"})
        public void test() {
            ProcessInstance processInstance = runtimeService
                    .startProcessInstanceByKey("my-process");
            assertNotNull(processInstance);
            Task task = taskService.createTaskQuery().singleResult();
            taskService.complete(task.getId());
        }
    
    
    }
    
  • activiti-content.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.spring.SpringProcessEngineConfiguration">
            <!--连接数据源-->
            <property name="dataSource" ref="dataSource"/>
            <!--连接事物管理-->
            <property name="transactionManager" ref="transactionManager"/>
            <!--数据源创建格式-->
            <property name="databaseSchemaUpdate" value="true"/>
        </bean>
    
        <!--新建数据源-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url" value="jdbc:h2:mem:activiti"/>
            <property name="driverClassName" value="org.h2.Driver"/>
            <property name="username" value="sa"/>
            <property name="password" value=""/>
        </bean>
    
        <!--事物管理-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <!--构造流程引擎对象-->
        <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
            <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
        </bean>
        <!--获取流程引擎对象后把服务暴露给Spring-->
        <!--基Sping原理-->
        <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
        <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
        <bean id="formService" factory-bean="processEngine" factory-method="getFormService"/>
        <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
        <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
    
        <!--配置ActivityRule,主要是为测试使用的rule-->
        <bean id="acitvityRule" class="org.activiti.engine.test.ActivitiRule">
            <property name="processEngine" ref="processEngine"/>
        </bean>
    </beans>
    
    
    
    
  • 执行结果

image-20210212180929723.png

image-20210212180939008.png

Activiti与spring集成-3

  • my-process_spring.bpmn20.xml

        <process id="my-process">
    
            <startEvent id="start"/>
            <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>
            <serviceTask id="someTask" name="Activiti is awsome!"/>
            <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>
            <serviceTask id="hellobean" activiti:expression="${helloBean.sayHello()}"/>
            <sequenceFlow id="flow3" sourceRef="hellobean" targetRef="end"/>
            <endEvent id="end"/>
    
        </process>
    
  • HelloBean

public class HelloBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(HelloBean.class);

    public void sayHello() {
        LOGGER.info("sayHello");
    }
}
  • 配置helloBean

image-20210212192709941.png