An overview of the

Activiti process engine configuration

The role of the process engine configuration class

ProcessEngineConfiguration

  • Locate and parse the XML configuration file activiti.cfg.xml
  • Provides multiple static methods to create configuration objects
  • The realization of several subclasses based on different scenarios, flexible configuration

activiti.cfg.xml

Static methods create configuration objects

Multiple subclasses are suitable for different scenarios

ProcessEngineConfiguration class

  • ProcessEngineConfigurationImpl it isn’t an implementation class is an abstract class, configure ProcessEngineConfiguration properties and some get eighty percent, set method
  • StandloneProcessEngineConfiguration, according to a new way to create objects using Java code calls the strategy method
  • SpringProcessEngineConfiguration integration based on Spring Spring extended data sources in its function, extension set a a things that can be loaded directory

Create process engine configuration -archetype

Create scaffolding

  • Project directory location activiti-boot2 / Tooling /activiti-archetype-unittest

With the configuration – config_samples

Create the process engine configuration -config_samples

createProcessEngineConfigurationFromResourceDefault

  • The following code
public class ConfigTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigTest.class);

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

        LOGGER.info("configuration = {}", configuration); }}Copy the code
  • The log output is as follows

    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. The impl. CFG. Fedbd StandaloneInMemProcessEngineConfiguration @ 279  ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= c.ConfigTest.testConfig1:21Copy the code

    Log analysis is as follows

createStandaloneInMemProcessEngineConfiguration

The following code

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

The log is printed as follows

10:15:47. 331 [main] [INFO] configuration = org. Activiti. Engine. The impl. CFG. E94dcf StandaloneInMemProcessEngineConfiguration @ 78  ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= c.ConfigTest.testConfig2:28Copy the code

Log analysis is as follows

Source code analysis

createStandaloneInMemProcessEngineConfiguration

ProcessEngineConfiguration
        .createStandaloneInMemProcessEngineConfiguration()
Copy the code
  • The underlying source code is analyzed

  • Essentially calling the H2 database

  • Do not rely on the Spring

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

createProcessEngineConfigurationFromResourceDefault

  • Click on the next layer of source code

    public static ProcessEngineConfiguration createProcessEngineConfigurationFromResourceDefault(a) {
            return createProcessEngineConfigurationFromResource("activiti.cfg.xml"."processEngineConfiguration");
        }
    Copy the code

  • Get the Resource file from the classPath

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

  • Together with the SpringBean file

    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;
        }
    Copy the code

ProcessEngineConfiguration source code analysis

ProcessEngineConfigurationImp is ProcessEngineConfiguration class inheritance

  // false does not modify the database
  public static final String DB_SCHEMA_UPDATE_FALSE = "false";
  // Create destruct at startup time
  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";

  // Integrate mail configuration
  protected String mailServerHost;
  protected String mailServerUsername;
  protected String mailServerPassword;

  // The H2 database is used by default and is not recommended for production environments
  this.databaseSchemaUpdate = "false";
  this.jdbcDriver = "org.h2.Driver";
  this.jdbcUrl = "jdbc:h2:tcp://localhost/~/activiti";

  // Generate flowchart to set font
   this.xmlEncoding = "UTF-8";
   this.defaultCamelContext = "camelContext";
   this.activityFontName = "Arial";
   this.labelFontName = "Arial";
   this.annotationFontName = "Arial";

  // A tool to generate a rendering of the flowchart
  public ProcessDiagramGenerator getProcessDiagramGenerator(a) {
      return this.processDiagramGenerator;
  }

 // Configure the database table name generation
 this.databaseTablePrefix = "";
Copy the code

The most important method

  @Override
  public ProcessEngine buildProcessEngine(a) {
    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;
  }
Copy the code
  • init()

    public void init(a) {
        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();
      }
    Copy the code

SpringProcessEngineConfiguration

Database configuration -dbconfig

Database Configuration

  • It is the default configuration to use an H2 in-memory database

  • Configure the JDBC properties to use the connection pool provided by Mybatis

  • Configure DataSource, optional third-party implementation

  • Configure JDBC properties using connection pooling provided by Mybatis

Original Data Configuration

  • Configure the DataSource for the third-party implementation

  • Druid Data source connection pool

Supported database types

  • Configuration databaseType

Database update Strategy

  • Configuration dataSourceSchemaUpdate

Database configuration – dbCONFIG_code

Create the data source using the default data

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

    @Test
    public void testConfig1(a) {
        ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
        LOGGER.info("cfg = {}", cfg);
        ProcessEngine processEngine = cfg.buildProcessEngine(); // Create engine
        LOGGER.info("Get process engine {}", processEngine.getName()); processEngine.close(); }}Copy the code

  • Activiti. CFG. XML configuration

    
            
    <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"/> <! -- To avoid forgetting to add this -->
            <! -- <property name="databaseSchemaUpdate" value="true"/>--><! -- This configuration will be executed even if there are tables in the database, but the dirty data left by unit tests will be left in the database.
        </bean>
    
    </beans>
    
    Copy the code

Using a DataSource

  • Use the Druid data source
  • JavaTest code
    @Test
    public void testConfig2(a) {
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti_druid.cfg.xml");
        LOGGER.info("processEngineConfiguration = {}", processEngineConfiguration);
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        LOGGER.info("Get process engine = {}", processEngine.getName());
        processEngine.close();
    }
Copy the code
  • activiti_druid.cfg.xml

    
            
    <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">
            <! -- This configuration will be executed even if there are tables in the database, but the dirty data left by unit tests will be left in the database.
            <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>
    
    Copy the code

Logging configuration -logging

Relationship level MDC of the log component

The logging component

Log recording and MDC

Configuring MDC(Mapped Diagnostic Contexts)
  • By default, logmdC.setMDcenable (true) is disabled.
  • Configure logback. XML logging template %X{mdcProcessInstanceID}
  • MDC information is recorded only when exceptions occur during process execution
Configuration HistoryLevel
  • None: Indicates that historical flows are not recorded and cannot be read after flows are complete
  • Activiti: Archive process instances and activity instances, process variables out of sync
  • Audit: Default value to synchronize variable values based on Acitviti and save single table properties
  • Full: Poor performance, records all instance and variable details

Configure db-based event logging

Configure the Event Logging
  • Experimental event logging mechanism has a significant performance impact
  • Enable the process of recording all data changes by default. Table records grow rapidly
  • Log content is in JSON format. MogoDB, Elastic Search is recommended

Log configuration -logging_mdc

Java configuration test classes

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(a) {
        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()); }}Copy the code

my-process.bpmn20.xml


      

<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>
Copy the code

Test exception class

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"); }}Copy the code

History configuration -history-1

The Java code and XML code are as follows

  • 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(a) {
        // Start the process
        startProcessInstance();

        // Modify variables
        changeVariable();

        // Submit the form task
        submitTaskFormData();

        // Output history content
        // Output history activity
        showHistoryActivity();

        // Outputs the history variable
        showHistoryVariable();

        // Outputs historical user tasks
        showHistoryTask();

        // Outputs the history form
        showHistoryForm();

        // Output history details
        showHistoricDetails();

    }

    private void showHistoricDetails(a) {
        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(a) {
        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(a) {
        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(a) {
        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(a) {
        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(a) {
        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(a) {
        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(a) {
        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) {
        returnToStringBuilder.reflectionToString(historicDetail, ToStringStyle.SHORT_PREFIX_STYLE); }}Copy the code
  • activiti_history.cfg.xml

    
            
    <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>
    
    Copy the code
  • Interceptor (MDCComandInvoker)

    public class MDCComandInvoker extends DebugCommandInvoker {
        @Override
        public void executeOperation(Runnable runnable) {
            boolean mdcEnabled = LogMDC.isMDCEnabled(); // Get whether it takes effect
            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); }}}Copy the code
  • The test results

Event handling and listener configuration -eventlog

Java code and XML code

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(a) {
        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()); }}Copy the code
  • activiti_eventlog.cfg.xml

      
<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>

Copy the code

Event handling and listener configuration -eventLinstener-1

Principle of listener

  • The listener
  • Event source: is a process engine object
  • Event type: Create type

Listener configuration mode

Configure the Listener

  • EventListener: Listens for all events and sends notifications
  • TypeEventListerners: Listens for notifications of specified event types
  • Activiti :eventListener: Only listens for specific process events

Activiti event listening

The relevant API

  • ActivitiEvent: Monitors events
  • ActivitiEventListener: Listener (listener abstract interface for all classes)
  • ActivitiEventType: Event type (an enumeration type)

Event handling and listener configuration -eventLinstener-2

How the listener is configured

Activiti event listening

Command interceptor configuration-command-1

Command mode and responsibility chain mode

Command mode

Chain of Responsibility model

Command interceptor configuration

Configure Interceptor
  • Before the default interceptor customPreCommandInterceptors: configuration
  • After the default interceptor customPostCommandInterceptors: configuration
  • CommandInvoke: Configures the last interceptor

How interceptors are configured

  • Java code

    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(a) {
            ProcessInstance processInstance = activitiRule.getRuntimeService()
                    .startProcessInstanceByKey("my-process"); Task task = activitiRule.getTaskService().createTaskQuery().singleResult(); activitiRule.getTaskService().complete(task.getId()); }}Copy the code
  • activiti_intercptor.cfg.xml

    
            
    <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"/><! -- Log what process -->
            <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>
    
    Copy the code
  • The execution result

Job executor configuration -job-1

Configuration of job executor

  • AsyncExecutorActivitate: Activates the job executor
  • AsyncExecutorXXX: Asynchronous executor property configuration
  • AsyncExecutor: Asynchronous executor Bean

Customize the thread pool ExecutorService

  • CorePoolSize: number of core threads
  • MaxPoolSize: indicates the maximum number of threads
  • QueueCapacity: size of blocking queue

Timer Start Event

  • TimeDate: specifies the start time
  • TimeDuration: executes after specifying a duration interval
  • TimeCycle :R5/P1DT1H Specifies that events are executed later

Job executor configuration -job-2

Configure a custom thread pool

    <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>
Copy the code
  • activiti_job.cfg.xml

      
<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"/>
        <! -- Asynchronous activator -->
        <property name="asyncExecutorActivate" value="true"/>
        <! -- Asynchronous actuator -->
        <property name="asyncExecutor" ref="asyncExecutor"/>
        <! -- Configure event listening -->
        <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>

Copy the code
  • my-process_job.bpmn20.xml

        <process id="my-process">
    
            <! -- <startEvent id="start"/>-->
            <startEvent id="start">
                <timerEventDefinition>
                    <timeCycle>R5/PT10S</timeCycle><! -- execute every 10 seconds -->
                </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>
    Copy the code
  • 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(a) throws InterruptedException {
            LOGGER.info("start");
            List<Job> jobList = activitiRule.getManagementService().createTimerJobQuery().listPage(0.100);
            for (Job job : jobList) {
                LOGGER.info("Scheduled task = {}, default retries = {}", job, job.getRetries());
            }
            LOGGER.info("jobList.size() = {}", jobList.size());
            Thread.sleep(1000*1000);
            LOGGER.info("end"); }}Copy the code
  • 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("Listen for Job event {}\t {}", eventType,event.getProcessInstanceId() ); }}@Override
        public boolean isFailOnException(a) {
            return false; }}Copy the code
  • The execution result

Activiti integration with Spring -1

Integrated Spring configuration

The related configuration

  • Add poM dependency activit-Spring
  • The default configuration based on Spring is Activiti-content.xml
  • Acitiviti core services are injected into Spring

features

  • Integrate Sping transaction manager
  • Define file expressions to use Spring beans
  • Automatically deploy resource files

Unit testing

  • Add POM dependencies on Spring-test
  • Helper test Rule: ActivitiRule
  • TestCase: SpringActivitiTestCase (an early Junit3 extension)

Spring based management of 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(a) {
            ProcessInstance processInstance = runtimeService
                    .startProcessInstanceByKey("my-process"); assertNotNull(processInstance); Task task = taskService.createTaskQuery().singleResult(); taskService.complete(task.getId()); }}Copy the code
  • activiti-content.xml

    
            
    <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">
            <! Connect to the data source -->
            <property name="dataSource" ref="dataSource"/>
            <! -- Connect transaction management -->
            <property name="transactionManager" ref="transactionManager"/>
            <! -- Data source creation format -->
            <property name="databaseSchemaUpdate" value="true"/>
        </bean>
    
        <! Create a new data source -->
        <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>
    
        <! -- Business management -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <! Create a process engine object -->
        <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
            <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
        </bean>
        <! Get the process engine object and expose the service to Spring.
        <! -- Sping principle -->
        <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"/>
    
        <! -- Configure ActivityRule, mainly for testing rule-->
        <bean id="acitvityRule" class="org.activiti.engine.test.ActivitiRule">
            <property name="processEngine" ref="processEngine"/>
        </bean>
    </beans>
    
    
    
    Copy the code
  • The execution result

Activiti with Spring integration -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>
    Copy the code
  • HelloBean

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

    public void sayHello(a) {
        LOGGER.info("sayHello"); }}Copy the code
  • Configuration helloBean