转载

Activiti 用户指南(Spring集成)

Spring集成

可以将 ProcessEngine 配置为常规的Spring bean,集成的起点是类 org.activiti.spring.ProcessEngineFactoryBean ,该bean进行流程引擎配置并创建流程引擎,对于Spring集成,配置和引擎bean如下所示:

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

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

注意, processEngineConfiguration bean现在使用 org.activiti.spring.SpringProcessEngineConfiguration 类。

事务

我们将逐步介绍在分发示例中找到的 SpringTransactionIntegrationTest ,以下是我们在此示例中使用的Spring配置文件(你可以在 SpringTransactionIntegrationTest-context.xml 中找到它),下面显示的部分包含 dataSourcetransactionManagerprocessEngine 和Activiti Engine服务。

当将数据源传递给 SpringProcessEngineConfiguration 时(使用属性“ dataSource ”),Activiti在内部使用 org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy 来包装传递的 DataSource ,这样做是为了确保从数据源检索的SQL连接和Spring事务能够很好地协同工作。这意味着虽然仍然允许将 TransactionAwareDataSourceProxy 传递到 SpringProcessEngineConfiguration 中,但不再需要在Spring配置中自行代理 dataSource ,在这种情况下,将不会发生其他包装。

确保自己在Spring配置中声明 TransactionAwareDataSourceProxy 时,不要将其用于已经知道Spring事务的资源(例如 DataSourceTransactionManagerJPATransactionManager 需要未代理的数据源)。

<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="asyncExecutorActivate" 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配置文件的其余部分包含我们将在此特定示例中使用的Bean和配置:

<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方法来创建应用程序上下文,在此示例中,你可以使用类路径XML资源来配置我们的Spring应用程序上下文:

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

或由于它是测试:

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

然后我们可以获取服务bean并在其上调用方法, ProcessEngineFactoryBean 将向应用传播的服务添加一个额外的拦截器,Activiti服务方法上所需的事务语义,因此,例如,我们可以使用 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();

UserBean 看起来像这样,记住,在上面的Spring bean配置中,我们将 runtimeService 注入到 userBean 中。

public class UserBean {

  /** injected by Spring */
  private RuntimeService runtimeService;

  @Transactional
  public void hello() {
    // here you can do transactional stuff in your domain model
    // and it will be combined in the same transaction as
    // the startProcessInstanceByKey to the Activiti RuntimeService
    runtimeService.startProcessInstanceByKey("helloProcess");
  }

  public void setRuntimeService(RuntimeService runtimeService) {
    this.runtimeService = runtimeService;
  }
}

表达式

默认情况下,使用 ProcessEngineFactoryBean 时,BPMN流程中的所有表达式也将看到所有Spring Bean。你可以使用可配置的映射来限制要在表达式中公开的bean,甚至根本不公开任何bean。下面的示例展示了一个单一的bean( printer ),可在键“ printer ”下使用。要完全不暴露任何bean,只需在 SpringProcessEngineConfiguration 上传递一个空列表作为beans属性,如果未设置bean属性,则上下文中的所有Spring bean将可用。

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

现在,可以在表达式中使用暴露的bean:例如, SpringTransactionIntegrationTesthello.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 。此属性定义了从与过滤器匹配的资源集中确定部署的方式,此属性默认支持3个值:

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

除了将上面列出的值用于 deploymentMode 之外,你可能还需要自定义行为来确定部署,如果是这样,则可以创建 SpringProcessEngineConfiguration 的子类并重写 getAutoDeploymentStrategy(String deploymentMode) 方法,此方法确定将哪种部署策略用于 deploymentMode 配置的特定值。

单元测试

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

  }
}

注意,要使此方法起作用,你需要在Spring配置中定义一个 org.activiti.engine.test.ActivitiRule bean(在上面的示例中通过自动装配注入)。

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

JPA与Hibernate 4.2.x

在Activiti Engine中的服务任务或侦听器逻辑中使用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>
原文  https://segmentfault.com/a/1190000021339821
正文到此结束
Loading...