Activiti工作流学习-----基于5.19.0版本(5)

五、与Spring集成

实际项目中一般都有Spring的身影,与Spring集成使得Activiti的实用性得到提高。activiti和Spring整合需要activiti-spring的jar在类路径下面,整合类是:org.activiti.spring.ProcessEngineFactoryBean,它将加载配置对象和产生流程引擎对象。例如下面代码:

<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    ...
</bean>

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

5.1 事务的配置

在xml配置SpringProcessEngineConfiguration的dataSource的时候,实际上工作流使用的是org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy,它是dataSource的一个增强类,它的作用就是确定从dataSource中获取的数据库连接已经绑定了Spring的事务,所以你无需在进行配置dataSource的代理类,以防失去TransactionAwareDataSourceProxy的效果。

确保在配置中没有配置TransactionAwareDataSourceProxy,因为它在Spring的事务中不会有作用(比如DataSourceTransactionManager和JPATransactionManager不需要代理的dataSource)。

 1 <beans xmlns="http://www.springframework.org/schema/beans"
 2        xmlns:context="http://www.springframework.org/schema/context"
 3        xmlns:tx="http://www.springframework.org/schema/tx"
 4        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5        xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
 6                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
 7                            http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
 8
 9   <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
10     <property name="driverClass" value="org.h2.Driver" />
11     <property name="url" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
12     <property name="username" value="sa" />
13     <property name="password" value="" />
14   </bean>
15
16   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
17     <property name="dataSource" ref="dataSource" />
18   </bean>
19
20   <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
21     <property name="dataSource" ref="dataSource" />
22     <property name="transactionManager" ref="transactionManager" />
23     <property name="databaseSchemaUpdate" value="true" />
24     <property name="jobExecutorActivate" value="false" />
25   </bean>
26
27   <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
28     <property name="processEngineConfiguration" ref="processEngineConfiguration" />
29   </bean>
30
31   <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
32   <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
33   <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
34   <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
35   <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
36
37 ...

在其他的Spring配置文件中配置其他的,这样功能清晰,后期容易维护,例如:

 1 <beans>
 2   ...
 3   <tx:annotation-driven transaction-manager="transactionManager"/>
 4
 5   <bean id="userBean" class="org.activiti.spring.test.UserBean">
 6     <property name="runtimeService" ref="runtimeService" />
 7   </bean>
 8
 9   <bean id="printer" class="org.activiti.spring.test.Printer" />
10
11 </beans>

在Spring中启动容器(application context)的方法有很多,比如下面利用类路径加载配置文件:

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

而在单元测试中,我们可以这样:

1 @ContextConfiguration("classpath:org/activiti/spring/test/transaction/SpringTransactionIntegrationTest-context.xml")

在Spring的IOC容器中我们可以轻易的获取我们需要的工作流的Service,ProcessEngineFactoryBean实现了对这些Service的Propagation.REQUIRED的事务级别的控制,例如下面这段代码:

1 RepositoryService repositoryService =
2   (RepositoryService) applicationContext.getBean("repositoryService");
3 String deploymentId = repositoryService
4   .createDeployment()
5   .addClasspathResource("org/activiti/spring/test/hello.bpmn20.xml")
6   .deploy()
7   .getId();

在其他方面也有同样的效果,在下面这种情况中,Spring的事务是环绕在serBean.hello()中,这时Activiti的Service会加入事务当中。

UserBean userBean = (UserBean) applicationContext.getBean("userBean");
userBean.hello();

而在具体的UserBean中,我们通过前面的配置是注入了RuntimeService:

 1 public class UserBean {
 2
 3   /** Spring注入 */
 4   private RuntimeService runtimeService;
 5
 6   @Transactional
 7   public void hello() {
 8     // here you can do transactional stuff in your domain model
 9     // and it will be combined in the same transaction as
10     // the startProcessInstanceByKey to the Activiti RuntimeService
11     runtimeService.startProcessInstanceByKey("helloProcess");
12   }
13
14   public void setRuntimeService(RuntimeService runtimeService) {
15     this.runtimeService = runtimeService;
16   }
17 }

5.2 Spring中使用表达式

在Spring的配置中也有像activiti的表达式使用,有可能表达式中的bean有限制,在使用Map配置发现没有bean可用,在SpringProcessEngineConfiguration的beans属性配置Map时,如果里面的bean不存在也会通过,只不过bean为空而已。下面这段代码配置beans属性:

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

现在我们可以在xxxbpmn.xml文件中可以直接使用printer了:

<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中配置:

<beans>
  ...

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

</beans>

5.3 使用Spring实现自动发布

 自动发布流程定义是整合Spring后的功能,在流程引擎被创建的时候就会将spring配置的资源加载发布。为了防止重复发布,整合的jar中添加了过滤功能,只有加载的资源真正的被改变,才会重新发布。好处在于一些场景(junit 测试)下,Spring容器经常重启。

例如下面配置,其中deploymentResources属性设置资源路径。

<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提供了自定义发布的功能,在bean节点:SpringProcessEngineConfiguration添加属性deploymentMode,目前它有三种取值策略:

  • default:没有定义deploymentMode时,系统默认设置为default.
  • single-resource:每个资源文件单独发布,如果资源文件改变,单独发布。
  • resource-parent-folder:每个资源文件夹单独发布,也就是说在不同文件夹下的资源文件将会以不同的文件夹为单位,进行防重复发布功能的发布。它介于default(批量发布)和single-resource(单个发布)之间。

以上就是所有的deploymentMode取值,如果你觉得不能够满足你的需求,你可以继承SpringProcessEngineConfiguration,重写其中的getAutoDeploymentStrategy(String deploymentMode)方法实现自己的功能。

5.4 在Spring环境的单元测试

前面介绍过activiti自己提供的测试方法,而在Spring中进行单元测试的话,可以这样:

@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());

  }
}

不过值得注意的是你测试之前需要将org.activiti.engine.test.ActivitiRule配置注册到Spring的文件中,它会在上述例子中自动注入到测试中。

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

目前本人使用Spring-Boot不多(就没怎么用),至于Spring-Boot和Activiti的集成,感兴趣的同学可以自己去了解,反正我觉得太过于封装的东西不要太过于追求。

六、 工作流动态发布

将流程定义等资源文件以zip压缩格式打包后,activiti引擎将会去扫描含有.bpmn20.xml 或者 .bpmn扩展名的文件,这些文件将会被识别解析。但注意不要将java文件以及编译后文件也加到打包文件中,流程引擎只会加载当前类路径下面的类文件,同时加到打包文件的class文件也不会被加到类路径下面去。

这时后台需要代码实现发布功能,比如这样:

String barFileName = "path/to/process-one.bar";
ZipInputStream inputStream = new ZipInputStream(new FileInputStream(barFileName));

repositoryService.createDeployment()
    .name("process-one.bar")
    .addZipInputStream(inputStream)
    .deploy();

在官方提供的Activiti Explorer项目中也有动态发布功能集成,将其项目部署到tomcat后,我使用了管理员Kermit登录系统,点击管理-->部署包--->添加新的部署包

弹出一个上传文件的弹出框:

而我们资源打包文件引用到的类需要放到流程引擎的classpath下面.

6.1 流程定义的版本

BPMN是没有版本的概念的,bpmn文件交给版本控制软件(比如SVN,git,Mercurial)进行管理,这样子设计方便我们对项目的集中管理,而存入数据库的流程定义的版本是工作流在发布期间标识的版本。每一个流程定义写进数据库需要初始化这些属性:key, version, name 和id。

id的值来自流程配置文件的key值。name值来自于流程配置文件的name值,第一次发布默认version是1,随后的发布会将版本递增。id的取值是{流程定义的key值}:{流程定义的版本}:{随机数},而这个随机数在分布式环境中也是保证是唯一的。

比如下面这个流程配置文件:

1 <definitions id="myDefinitions" >
2   <process id="myProcess" name="My important process" >

发布过后在数据库中保存的数据就是这样:

id key name version

myProcess:1:676


myProcess


My important process


1

假使我们重新发布了流程配置文件,但文件中id的值并没有修改,数据库中的数据变成了这样子:


myProcess:1:676


myProcess


My important process


1


myProcess:2:870


myProcess


My important process


2

如果我们修改了id,再次发布数据库数据就成这样子:

id key name version

myProcess:1:676


myProcess


My important process


1


myProcess:2:870


myProcess


My important process


2


myNewProcess:1:1033


myNewProcess


My important process


1

可以看出发布区分新的流程配置会根据key进行判断,Activiti仅仅会根据key值的不同进行区分,所以流程版本变成了1。

6.2 添加流程图发布

发布过程中可以添加流程图进去, 流程图会被视为资源而保存起来,流程图主要用在Activiti Explorer的页面中显示给用户查看。假定我们有一个流程的xml文件在类路径下面,activiti使用命名规则进行获取流程图:

  • 如果流程图已经存在并且使用流程配置文件名作为图片名称,当然后缀名是git、jpg、png都可以,将会被获取加载,如果有其他名称的图片文件,将会被忽视。
  • 如果图片文件在当前流程配置文件的同一个目录里面不存在。

人工添加流程图代码实现就是如下所示:

1 repositoryService.createDeployment()
2   .name("expense-process.bar")
3   .addClasspathResource("org/activiti/expenseProcess.bpmn20.xml")
4   .addClasspathResource("org/activiti/expenseProcess.png")
5   .deploy();

取出图片资源代码实现:

1 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
2   .processDefinitionKey("expense")
3   .singleResult();
4
5 String diagramResourceName = processDefinition.getDiagramResourceName();
6 InputStream imageStream = repositoryService.getResourceAsStream(
7     processDefinition.getDeploymentId(), diagramResourceName);

如果bpmn文件中含有必要的信息,activiti将会生成流程图片,如果不想生成可以设置:

<property name="createDiagramOnDeploy" value="false" />

bpmn文件可以被用户进行自定义分类,帮助用户自己识别使用,在bpmn文件的:<definitions …? targetNamespace="yourCategory" 可以设置。

如果使用代码实现这个功能可以这样:

1 repositoryService
2     .createDeployment()
3     .category("yourCategory")
4     ...
5     .deploy();
时间: 2024-08-18 00:22:31

Activiti工作流学习-----基于5.19.0版本(5)的相关文章

Activiti工作流学习-----基于5.19.0版本(8)

8.1.5 Start Event 继续上一篇的事件的分享笔记,Start Event指明该处是流程开始,至于开始事件的类型(消息到达开始,指定的事件循环开始等),定义如何开始是在开始事件圆圈图标里面的小图标表示,具体反映到xml中就是子元素的不同. Start Event总是进行捕获:在任何时候等待相应的触发器触发. 下面展示start event的xml,其中initiator指的是流程发起人,流程开始后他将会被保存起来: <startEvent id="request" a

Activiti工作流学习-----基于5.19.0版本(6)

七. BPMN的简介 读者了解到这里,应付一般的工作流开发已经足够了.此处应该有华丽的分割线,在工作流项目中核心开发人员主要是对工作流业务设计以及实现,而初级开发人员是对业务功能的代码实现.以后将主要对流程图设计的概念和具体设计进行描述,如果你感兴趣可以继续了解. 7.1 什么是BPMN? BPMN的全称是Business Process Model and Notation,它是一套BPM的规范,从2004年起,BPMN规范的推动有OMG组织维护,开始推出的BPMN1.0主要是对设计图中图形的

Activiti工作流学习-----基于5.19.0版本(2)

二.activiti.cfg.xml的其他bean节点配置 2.1 新特性:Job Executor和Async Executor 从5.17.0版本的activiti开始提供作业执行者(Job Executor)和异步作业执行者(Async Executor),Async Executor执行表现更好,并且执行异步作业对数据库更加友善.activiti官方推荐使用Async Executor,并且一些老的Job Executor依旧有效.在Java EE 7运行环境中,JSR-236规范支持容

Activiti工作流学习-----基于5.19.0版本(1)

该版本的Activiti运行须知: 1.JDK 6+,Eclipse最好是Kepler以上版本. 2.试验功能都有EXPERIMENTAL标注,被标注的部分不应该视为稳定的. 有兴趣的同学可以去了解下Activiti Explorer项目,他涵盖了大部分Activiti的功能,还没有Activiti概念的同学可以看看了解一下. 一.工作流开发之配置 Activiti沿用具有Spring配置文件风格的配置,工作流默认是加载名叫activiti.cfg.xml的文件,配置文件大体: <beans x

Activiti工作流学习-----基于5.19.0版本(3)

前面关于eventType的属性值的配置简单的说了一下,activiti支持的值如下表所示:这是我摘抄的activiti官网的 Event 的名字 描述 Event的类名 ENGINE_CREATED The process-engine this listener is attached to, has been created and is ready for API-calls. org.activiti…?ActivitiEvent ENGINE_CLOSED The process-e

Activiti工作流学习(三)Activiti工作流与spring集成

一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用spring框架进行开发,现在来说明一下Activiti工作流与spring集成,Activiti工作流与spring集成还算比较简单,可以参考Activiti的API来进行整合. 二.Activiti常用的表 ---------------------------------------------部署对象

Activiti工作流学习(二)流程实例、执行对象、任务

一.前言 前面说明了基本的流程部署.定义,启动流程实例等基本操作,下面我们继续来学习流程实例.执行对象.任务. 二.流程实例.执行对象说明 整个Activiti的生命周期经过了如下的几个步骤: 1.流程部署 --->  2.启动流程实例 --- > 3.执行流程对象(一个流程实例包含多执行对象) ---> 4.完成整个流程 说明: 三.例子演示   1.完成我的任务     2.查询流程状态(判断流程正在执行,还是结束) 3.查询历史任务  4.流程实例.执行对象.任务  四.对应数据库

Activiti工作流学习一安装和下载

1.下载和安装 1) 下载activiti相关jar包和文件 官方下载地址:http://www.activiti.org/download.html 2) Activiti-eclipse插件下载 1,手动下载==>官方下载地址:http://activiti.org/designer/update 2,自动下载==>运行eclipse,安装Activiti BPMN 2.0 designer插件,具体参见:http://www.ecmkit.com/zh-hans/2012/03/21/a

activiti工作流学习链接

首页: http://www.activiti.org/书籍: activiti in action  入门demo: kft-activiti-demo   http://www.oschina.net/p/kft-activiti-demo/论坛:http://www.activiti-cn.org/