如何打包Activiti的流程资源文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何打包Activiti的流程资源文件相关的知识,希望对你有一定的参考价值。

参考技术A Activiti的流程定义文件可以直接部署bpmn20.xml、zip、bar文件,其中后面的zip和bar类型一样都是压缩文件格式,bpmn20.xml是符合bpmn2.0规范的xml定义。 今天要解决的问题就是帮助大家打包流程资源文件,其中肯能包括:bpmn20.xml、png、form等...

Spring集成使用工作流框架Activiti!事务配置,注解配置以及流程资源自动化部署

Spring使用Activiti提供了一些非常不错的集成特性,只在Activiti与Spring集成时使用

ProcessEngineFactoryBean

  • 可以把流程引擎(ProcessEngine)作为一个普通的Spring bean进行配置
  • 类org.activiti.spring.ProcessEngineFactoryBean是集成的切入点,这个bean需要一个流程引擎配置来创建流程引擎
  • Spring集成的配置和流程引擎bean,使用的processEngineConfiguration bean是 org.activiti.spring.SpringProcessEngineConfiguration类:

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
      ...
    </bean>
    
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
    <property name="processEngineConfiguration" ref="processEngineConfiguration" />
    </bean>

    事务

  • 使用这个例子的Spring配置文件SpringTransactionIntegrationTest-context.xml:

    • dataSource: 数据源
    • transactionManager: 事务管理器
    • processEngine: 流程引擎
    • Activiti引擎服务
  • 当把数据源(DataSource)传递给SpringProcessEngineConfiguration(使用"dataSource"属性)之后,Activiti内部使用了一个org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy代理来封装传递进来的数据源(DataSource).这样做是为了确保从数据源(DataSource)获取的SQL连接能够与Spring的事物结合在一起发挥得更出色.这意味不需要在Spring配置中代理数据源(dataSource). 但是仍然允许传递一个TransactionAwareDataSourceProxy到SpringProcessEngineConfiguration中
  • 为了确保在Spring配置中声明的一个TransactionAwareDataSourceProxy,不能把使用它的应用交给Spring事物控制的资源(例如DataSourceTransactionManager和JPATransactionManager需要非代理的数据源)

    <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:tx="http://www.springframework.org/schema/tx"
         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
                             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                             http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
      <property name="driverClass" value="org.h2.Driver" />
      <property name="url" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
      <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="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
      <property name="dataSource" ref="dataSource" />
      <property name="transactionManager" ref="transactionManager" />
      <property name="databaseSchemaUpdate" value="true" />
      <property name="jobExecutorActivate" value="false" />
    </bean>
    
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
      <property name="processEngineConfiguration" ref="processEngineConfiguration" />
    </bean>
    
    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
    <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
    <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
    <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
    <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
    
    ...
  • Spring配置文件的其余部分包含beans和在特有的例子中的配置:

    <beans>
    ...
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <bean id="userBean" class="org.activiti.spring.test.UserBean">
      <property name="runtimeService" ref="runtimeService" />
    </bean>
    
    <bean id="printer" class="org.activiti.spring.test.Printer" />
    
    </beans>
  • 首先使用任意的一种Spring创建应用上下文的方式创建其Spring应用上下文.可以使用类路径下面的XML资源来配置我们的Spring应用上下文:

    ClassPathXmlApplicationContext applicationContext =
      new ClassPathXmlApplicationContext("org/activiti/examples/spring/SpringTransactionIntegrationTest-context.xml");

    或者

    @ContextConfiguration("classpath:org/activiti/spring/test/transaction/SpringTransactionIntegrationTest-context.xml")
  • 然后我们就可以得到Activiti的服务beans并且调用该服务上面的方法,ProcessEngineFactoryBean将会对该服务添加一些额外的拦截器,在Activiti服务上面的方法使用的是Propagation.REQUIRED事物语义. 可以使用repositoryService去部署一个流程:

    RepositoryService repositoryService = (RepositoryService) applicationContext.getBean("repositoryService");
    String deploymentId = repositoryService
    .createDeployment()
    .addClasspathResource("org/activiti/spring/test/hello.bpmn20.xml")
    .deploy()
    .getId();   
  • 其他相同的服务也是同样可以这么使用.在这个例子中,Spring的事务将会围绕在userBean.hello()上,并且调用Activiti服务的方法也会加入到这个事务中

    UserBean userBean = (UserBean) applicationContext.getBean("userBean");
    userBean.hello();
  • 在上面Spring bean的配置中把repositoryService注入到userBean中

    public class UserBean {
    
    /** 由Spring注入 */
    private RuntimeService runtimeService;
    
    @Transactional
    public void hello() {
          //这里,你可以在你们的领域模型中做一些事物处理。
          //当在调用Activiti RuntimeService的startProcessInstanceByKey方法时,
          //它将会结合到同一个事物中。
      runtimeService.startProcessInstanceByKey("helloProcess");
    }
    
    public void setRuntimeService(RuntimeService runtimeService) {
      this.runtimeService = runtimeService;
    }
    }

    表达式

  • 当使用ProcessEngineFactoryBean时候,默认情况下,在BPMN流程中的所有表达式都将会"看见"所有的Spring beans. 可以限制在表达式中暴露出的beans或者甚至可以在配置中使用一个Map不暴露任何beans
  • 想要不暴露任何beans,只需要在SpringProcessEngineConfiguration中传递一个空的list作为\'beans\'的属性. 当不设置\'beans\'的属性时,在应用上下文中Spring beans都是可以使用的
  • 下面的例子暴露了一个单例bean(printer),可以把"printer"当作关键字使用:

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    ...
    <property name="beans">
      <map>
        <entry key="printer" value-ref="printer" />
      </map>
    </property>
    </bean>
    
    <bean id="printer" class="org.activiti.examples.spring.Printer" />
  • 现在暴露出来的beans就可以在表达式中使用:例如,在SpringTransactionIntegrationTest中的hello.bpmn20.xml展示的是如何使用UEL方法表达式去调用Spring bean的方法

    <definitions id="definitions" ...>
    
    <process id="helloProcess">
    
      <startEvent id="start" />
      <sequenceFlow id="flow1" sourceRef="start" targetRef="print" />
    
      <serviceTask id="print" activiti:expression="#{printer.printMessage()}" />
      <sequenceFlow id="flow2" sourceRef="print" targetRef="end" />
    
      <endEvent id="end" />
    
    </process>
    
    </definitions>
  • 这里的Printer类似这样:

    public class Printer {
    
    public void printMessage() {
      System.out.println("hello world");
    }
    }
  • Spring bean的配置类似这样:

    <beans ...>
    ...
    
    <bean id="printer" class="org.activiti.examples.spring.Printer" />
    
    </beans>

    资源自动部署

  • Spring的集成有专门针对对资源部署的特性
  • 在流程引擎的配置中,可以指定一组资源,当流程引擎被创建的时候,所有在这里的资源都将会被自动扫描与部署
  • 在这里有过滤以防止资源重新部署,只有当这个资源真正发生改变的时候,它才会向Activiti使用的数据库创建新的部署.
  • 这对于很多用例来说,当Spring容器经常重启的情况下,使用是非常不错的选择

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    ...
    <property name="deploymentResources" value="classpath*:/org/activiti/spring/test/autodeployment/autodeploy.*.bpmn20.xml" />
    </bean>
    
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
    <property name="processEngineConfiguration" ref="processEngineConfiguration" />
    </bean>

    默认情况下,上面的配置会把所有匹配的资源发布到Activiti引擎的一个单独发布包下.用来检测防止未修改资源重复发布的机制会作用到整个发布包中
    有时候,这可能不是想要的.比如,如果你发布了很多流程资源,但是只修改里其中某一个单独的流程定义,整个发布包都会被认为变更了,导致整个发布包下的所有流程定义都会被重新发布,结果就是每个流程定义都生成了新版本,虽然其中只有一个流程发生了改变

  • 为了定制发布方式, 可以为SpringProcessEngineConfiguration指定一个额外的参数deploymentMode. 这个参数指定了匹配多个资源时的发布处理方式. 默认下这个参数支持设置三个值:

    • default: 把所有资源放在一个单独的发布包中,对这个发布包进行重复检测.这是默认值,如果你没有指定参数值,就会使用它
    • single-resource: 为每个单独的资源创建一个发布包,并对这些发布包进行重复检测.你可以单独发布每个流程定义,并在修改流程定义后只创建一个新的流程定义版本
    • resource-parent-folder: 把放在同一个上级目录下的资源发布在一个单独的发布包中,并对发布包进行重复检测.当需要多资源时需要创建发布包;但是需要根据共同的文件夹来组合一些资源时,可以使用
  • 将deploymentMode参数配置为single-resource的情况:

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    ...
    <property name="deploymentResources" value="classpath*:/activiti/*.bpmn" />
    <property name="deploymentMode" value="single-resource" />
    </bean>
  • 如果想使用上面三个值之外的参数值,你需要自定义处理发布包的行为.可以创建一个SpringProcessEngineConfiguration的子类,重写getAutoDeploymentStrategy(String deploymentMode)方法. 这个方法中处理了对应deploymentMode的发布策略

    单元测试

  • 当集成Spring时,使用标准的Activiti测试工具类是非常容易地对业务流程进行测试:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:org/activiti/spring/test/junit4/springTypicalUsageTest-context.xml")
    public class MyBusinessProcessTest {
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Autowired
    @Rule
    public ActivitiRule activitiSpringRule;
    
    @Test
    @Deployment
    public void simpleProcessTest() {
      runtimeService.startProcessInstanceByKey("simpleProcess");
      Task task = taskService.createTaskQuery().singleResult();
      assertEquals("My Task", task.getName());
    
      taskService.complete(task.getId());
      assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    
    }
    }
  • 对于这种方式,需要在Spring配置中定义一个org.activiti.engine.test.ActivitiRulebean

    <bean id="activitiRule" class="org.activiti.engine.test.ActivitiRule">
    <property name="processEngine" ref="processEngine" />
    </bean>

    基于注解的配置

    除了基于XML的配置以外,还可以选择基于注解的方式来配置Spring环境.这与使用XML的方法非常相似,除了要使用@Bean注解.而且配置是使用java编写的, 可以直接用于Activiti-Spring的集成

  • @EnableActiviti: 会创建一个Spring环境,并对Activiti流程引擎进行配置

    • 默认的内存H2数据库,启用数据库自动升级
    • 一个简单的DataSourceTransactionManager
    • 一个默认的SpringJobExecutor
    • 自动扫描processes/ 目录下的bpmn20.xml文件

      @Configuration
      @EnableActiviti
      public static class SimplestConfiguration {
      
      }
  • 可以直接通过注入操作Activiti引擎:

     @Autowired
    private ProcessEngine processEngine;
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Autowired
    private HistoryService historyService;
    
    @Autowired
    private RepositoryService repositoryService;
    
    @Autowired
    private ManagementService managementService;
    
    @Autowired
    private FormService formService;
  • 默认值都可以自定义:

    • 如果配置了DataSource,就会代替默认创建的数据库配置
    • 事务管理器,ob执行器和其他组件都与之相同

      @Configuration
      @EnableActiviti
      public static class Config {
      
      @Bean
      public DataSource dataSource() {
          BasicDataSource basicDataSource = new BasicDataSource();
          basicDataSource.setUsername("sa");
          basicDataSource.setUrl("jdbc:h2:mem:anotherDatabase");
          basicDataSource.setDefaultAutoCommit(false);
          basicDataSource.setDriverClassName(org.h2.Driver.class.getName());
          basicDataSource.setPassword("");
          return basicDataSource;
      }
      
      }

      其他数据库会代替默认的

  • 注意AbstractActivitiConfigurer用法,它暴露了流程引擎的配置,可以用来对它的细节进行详细的配置:

    @Configuration
    @EnableActiviti
    @EnableTransactionManagement(proxyTargetClass = true)
    class JPAConfiguration {
    
      @Bean
      public OpenJpaVendorAdapter openJpaVendorAdapter() {
          OpenJpaVendorAdapter openJpaVendorAdapter = new OpenJpaVendorAdapter();
          openJpaVendorAdapter.setDatabasePlatform(H2Dictionary.class.getName());
          return openJpaVendorAdapter;
      }
    
      @Bean
      public DataSource dataSource() {
          BasicDataSource basicDataSource = new BasicDataSource();
          basicDataSource.setUsername("sa");
          basicDataSource.setUrl("jdbc:h2:mem:activiti");
          basicDataSource.setDefaultAutoCommit(false);
          basicDataSource.setDriverClassName(org.h2.Driver.class.getName());
          basicDataSource.setPassword("");
          return basicDataSource;
      }
    
      @Bean
      public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(
          OpenJpaVendorAdapter openJpaVendorAdapter, DataSource ds) {
          LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
          emf.setPersistenceXmlLocation("classpath:/org/activiti/spring/test/jpa/custom-persistence.xml");
          emf.setJpaVendorAdapter(openJpaVendorAdapter);
          emf.setDataSource(ds);
          return emf;
      }
    
      @Bean
      public PlatformTransactionManager jpaTransactionManager(
          EntityManagerFactory entityManagerFactory) {
          return new JpaTransactionManager(entityManagerFactory);
      }
    
      @Bean
      public AbstractActivitiConfigurer abstractActivitiConfigurer(
          final EntityManagerFactory emf,
          final PlatformTransactionManager transactionManager) {
    
          return new AbstractActivitiConfigurer() {
    
              @Override
              public void postProcessSpringProcessEngineConfiguration(SpringProcessEngineConfiguration engine) {
                  engine.setTransactionManager(transactionManager);
                  engine.setJpaEntityManagerFactory(emf);
                  engine.setJpaHandleTransaction(false);
                  engine.setJobExecutorActivate(false);
                  engine.setJpaCloseEntityManager(false);
                  engine.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
              }
          };
      }
    
      // A random bean
      @Bean
      public LoanRequestBean loanRequestBean() {
          return new LoanRequestBean();
      }
    }

    JPA和Hibernate

  • 在Activiti引擎的serviceTask或listener中使用Hibernate 4.2.x JPA时,需要添加Spring ORM依赖,Hibernate 4.1.x及以下版本是不需要的:

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${org.springframework.version}</version>
    </dependency>

以上是关于如何打包Activiti的流程资源文件的主要内容,如果未能解决你的问题,请参考以下文章

2017.2.28 activiti实战--第五章--用户与组及部署管理部署流程资源

Activiti应用实践-查询BPMN XML文件和图片资源文件

android app 打包流程

SpringBoot 集成Activiti 流程设计器

Spring集成使用工作流框架Activiti!事务配置,注解配置以及流程资源自动化部署

activiti6.0流程引擎部署方式之BpmnModel以及使用