5. 整合Spring

虽然你绝对可以在没有Spring的情况下使用Activiti,但是我们已经提供了一些非常好的集成特性,这些在本章中将会解释

5.1. ProcessEngineFactoryBean

ProcessEngine可以配置为普通的Spring bean。 整合的起点是类org.activiti.spring.ProcessEngineFactoryBean。 该bean采用流程引擎配置并创建流程引擎。 这意味着Spring的属性的创建和配置与配置部分中记录的相同。 对于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类。

5.2. Transactions

我们将逐步解释分布式Spring例子中的SpringTransactionIntegrationTest。 下面是我们在这个例子中使用的Spring配置文件(你可以在SpringTransactionIntegrationTest-context.xml中找到它)。 下面显示的部分包含dataSource,transactionManager,processEngine和Activiti引擎服务。

将DataSource传递给SpringProcessEngineConfiguration(使用属性“dataSource”)时,Activiti在内部使用一个org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy,它包装传递的DataSource。 这样做是为了确保从DataSource和Spring事务检索到的SQL连接能够很好地协同工作。 这意味着不再需要在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="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服务方法上应用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();

UserBean看起来像这样。 从上面的Spring bean配置中我们注意到repositoryService到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;
  }
}

5.3. 表达式

当使用ProcessEngineFactoryBean时,默认情况下,BPMN进程中的所有表达式都将看到所有的Spring bean。 可以限制要在表达式中公开的bean,或者甚至不使用可配置的映射公开任何bean。 下面的例子公开了一个单一的bean(打印机),可以在“打印机”键下使用。 为了让所有的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:例如,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看起来像这样:

results matching ""

    No results matching ""