Chapter 5. Spring 集成
虽然没有Spring你也可以使用Activiti,但是我们提供了一些非常不错的集成特性。这一章我们将介绍这些特性。
ProcessEngineFactoryBean
可以把流程引擎(ProcessEngine)作为一个普通的Spring bean进行配置。 类 org.activiti.spring.ProcessEngineFactoryBean是集成的切入点。 这个bean需要一个流程引擎配置来创建流程引擎。这也意味着在文档的配置这一章的介绍属性的创建和配置对于Spring来说也是一样的。对于Spring集成的配置和流程引擎bean看起来像这样:
1 | <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> |
注意现在使用的 processEngineConfiguration bean 是 org.activiti.spring.SpringProcessEngineConfiguration 类。
事务
我们将会一步一步地解释在Spring examples中公布的 SpringTransactionIntegrationTest 下面是我们使用这个例子的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需要非代理的数据源 )
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
Spring配置文件的其余部分包含beans和我们将要在这个特有的例子中的配置:
1 | <beans> |
首先使用任意的一种Spring创建应用上下文的方式创建其Spring应用上下文。在这个例子中你可以使用类路径下面的XML资源来配置我们的Spring应用上下文:
1 | ClassPathXmlApplicationContext applicationContext = |
或者, 如果它是一个测试的话:
1 | "classpath:org/activiti/spring/test/transaction/SpringTransactionIntegrationTest-context.xml") ( |
然后我们就可以得到Activiti的服务beans并且调用该服务上面的方法。ProcessEngineFactoryBean将会对该服务添加一些额外的拦截器,在Activiti服务上面的方法使用的是 Propagation.REQUIRED事物语义。所以,我们可以使用repositoryService去部署一个流程,如下所示:
1 | RepositoryService repositoryService = (RepositoryService) applicationContext.getBean("repositoryService"); |
其他相同的服务也是同样可以这么使用。在这个例子中,Spring的事物将会围绕在userBean.hello()上,并且调用Activiti服务的方法也会加入到这个事物中。
1 | UserBean userBean = (UserBean) applicationContext.getBean("userBean"); |
这个UserBean看起来像这样。记得在上面Spring bean的配置中我们把repositoryService注入到userBean中。
1 | public class UserBean { |
表达式
当使用ProcessEngineFactoryBean时候,默认情况下,在BPMN流程中的所有表达式都将会’看见’所有的Spring beans。 它可以限制你在表达式中暴露出的beans或者甚至可以在你的配置中使用一个Map不暴露任何beans。下面的例子暴露了一个单例bean(printer),可以把”printer”当作关键字使用. 想要不暴露任何beans,仅仅只需要在SpringProcessEngineConfiguration中传递一个空的list作为’beans’的属性。当不设置’beans’的属性时,在应用上下文中Spring beans都是可以使用的。
1 | <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> |
现在暴露出来的beans就可以在表达式中使用:例如,在SpringTransactionIntegrationTest中的 hello.bpmn20.xml展示的是如何使用UEL方法表达式去调用Spring bean的方法:
1 | <definitions id="definitions" ...> |
这里的 Printer 看起来像这样:
1 | public class Printer { |
并且Spring bean的配置(如上文所示)看起来像这样:
1 | <beans ...> |
资源的自动部署
Spring的集成也有一个专门用于对资源部署的特性。在流程引擎的配置中,你可以指定一组资源。当流程引擎被创建的时候, 所有在这里的资源都将会被自动扫描与部署。在这里有过滤以防止资源重新部署,只有当这个资源真正发生改变的时候,它才会向Activiti使用的数据库创建新的部署。 这对于很多用例来说,当Spring容器经常重启的情况下(例如 测试),使用它是非常不错的选择。
这里有一个例子:
1 | <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> |
默认,上面的配置会把所有匹配的资源发布到Activiti引擎的一个单独发布包下。用来检测防止未修改资源重复发布的机制会作用到整个发布包中。 有时候,这可能不是你想要的。比如,如果你发布了很多流程资源,但是只修改里其中某一个单独的流程定义, 整个发布包都会被认为变更了,导致整个发布包下的所有流程定义都会被重新发布, 结果就是每个流程定义都生成了新版本,虽然其中只有一个流程发生了改变。
为了定制发布方式,你可以为SpringProcessEngineConfiguration指定一个额外的参数deploymentMode。
这个参数指定了匹配多个资源时的发布处理方式。默认下这个参数支持设置三个值:
- default: 把所有资源放在一个单独的发布包中,对这个发布包进行重复检测。 这是默认值,如果你没有指定参数值,就会使用它。
- single-resource: 为每个单独的资源创建一个发布包,并对这些发布包进行重复检测。 你可以单独发布每个流程定义,并在修改流程定义后只创建一个新的流程定义版本。
- resource-parent-folder: 把放在同一个上级目录下的资源发布在一个单独的发布包中,并对发布包进行重复检测。 当需要多资源需要创建发布包,但是需要根据共同的文件夹来组合一些资源时,可以使用它。
这儿有一个例子来演示将deploymentMode参数配置为single-resource的情况:
1 | <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> |
如果想使用上面三个值之外的参数值,你需要自定义处理发布包的行为。 你可以创建一个SpringProcessEngineConfiguration的子类,重写getAutoDeploymentStrategy(String deploymentMode)方法。 这个方法中处理了对应deploymentMode的发布策略。
单元测试
当集成Spring时,使用标准的Activiti测试工具类是非常容易的对业务流程进行测试。 下面的例子展示了如何在一个典型的基于Spring单元测试测试业务流程:
1 | (SpringJUnit4ClassRunner.class) |
注意对于这种方式,你需要在Spring配置中(在上文的例子中它是自动注入的)定义一个org.activiti.engine.test.ActivitiRulebean
1 | <bean id="activitiRule" class="org.activiti.engine.test.ActivitiRule"> |
基于注解的配置
@EnableActiviti注解相对较新,未来可能会有变更。
除了基于XML的配置以外,还可以选择基于注解的方式来配置Spring环境。 这与使用XML的方法非常相似,除了要使用@Bean注解, 而且配置是使用java编写的。 它已经可以直接用于Activiti-Spring的集成了:
首先介绍(需要Spring 3.0+)的是@EnableActiviti注解。 最简单的用法如下所示:
1 |
|
它会创建一个Spring环境,并对Activiti流程引擎进行如下配置:
- 默认的内存H2数据库,启用数据库自动升级。
- 一个简单的 DataSourceTransactionManager
- 一个默认的 SpringJobExecutor
- 自动扫描 processes/ 目录下的bpmn20.xml文件。
在这样一个环境里,可以直接通过注入操作Activiti引擎:
1 |
|
当然,默认值都可以自定义。比如,如果配置了DataSource,它就会代替默认创建的数据库配置。 事务管理器,job执行器和其他组件都与之相同。 比如如下配置:
1 |
|
其他数据库会代替默认的。
下面介绍了更加复杂的配置。注意AbstractActivitiConfigurer用法, 它暴露了流程引擎的配置,可以用来对它的细节进行详细的配置。
1 |
|
JPA 和 Hibernate 4.2.x
在Activiti引擎的serviceTask或listener中使用Hibernate 4.2.x JPA时,需要添加Spring ORM这个额外的依赖。 Hibernate 4.1.x及以下版本是不需要的。应该添加如下依赖:
1 | <dependency> |