Activiti User Guide -- Activit 用户指南 Part03

Chapter 4. Spring integration

第四章 Spring集成

Table of Contents

ProcessEngineFactoryBean

Transactions

Expressions

Automatic resource deployment

Unit testing

While you can use Activiti without Spring, we've provided some very nice integration features that are explained in this chapter.

当你不通过Spring来使用Activiti时,我们会提供非常漂亮的集成功能,在本章中我们会对它们进行解析。

ProcessEngineFactoryBean

ProcessEngineFactoryBean

The starting point of the integration is the class org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean. That bean implementsProcessEngine and takes care of building the process engine whenever Spring instantiates it.

首先我们要集成的类是org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBeanbean实现了ProcessEngine,并且在Spring实例化时负责构建流程引擎。

<bean id="processEngine" class="org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean">
  ...
</bean>
  Properties that you can configure on the ProcessEngineFactoryBean:

  ProcessEngineFactoryBean可以配置的属性包含了:

Transactions

事务

 

We'll explain the SpringTransactionIntegrationTest here step by step. Here is the spring configuration file that we use in this example (located in SpringTransactionIntegrationTest-context.xml). The quoted section contains the dataSource, transactionManager, processEngine and the Activiti Engine services.

下面我们一步一步的解释SpringTransactionIntegrationTest 。下面列出了我们在示例中所使用的spring的配置文件(存放在SpringTransactionIntegrationTest-context.xml文件中)。所列出的部分包含了dataSource, transactionManager, processEngine Activiti 引擎中的services

<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.TransactionAwareDataSourceProxy">
    <property name="targetDataSource">
      <bean 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>
    </property>
  </bean>

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
  </bean>
  
  <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
    <property name="dataBaseName" value="h2" />
    <property name="dataSource" ref="dataSource" />
    <property name="transactionManager" ref="transactionManager" />
    <property name="dbSchemaStrategy" value="check-version" />
  </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" />
  ...
  The remainder of that spring configuration file contains the beans and configuration that we'll use in this particular example:

Spring其它的配置则包含了我们示例中所配置的bean

...
  <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>
  First the application context is created with any of the Spring ways to do that. In this example we're using a classpath XML resource to configure our Spring application context:

第一个application context则是通过任意Spring方式来构建。在本示例中我们使用类路径下的XML资源文件的方式来创建我们的Spring application context

 

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

 

Then we can get the service beans and invoke methods on them. The ProcessEngineFactoryBean will have added an extra interceptor to the services that applies Propagation.REQUIRED transaction semantics on the Activiti service methods. So we can use for example the repositoryService to deploy a process like this:

接下来我们就可以获取相应的service bean并调用相应的方法。ProcessEngineFactoryBean添加了一个事务拦截器,为Activiti service中的方法实施Propagation.REQUIRED事务。因此我们像下面代码一样通过repositoryService来部署我们的流程:

RepositoryService repositoryService = (RepositoryService) applicationContext.getBean("repositoryService");
String deploymentId = repositoryService
  .createDeployment()
  .addClasspathResource("org/activiti/spring/test/hello.bpmn20.xml")
  .deploy()
  .getId();

 

The next section shows how invocation of the userBean. In this case, the Spring transaction will be around the userBean.hello() method and the Activiti service method invocation will join that same transaction.

下面的示例则是展示了如何调用userBean。在本示例中,userBean.hello()中则会织入Spring事务,并且Activiti所提供的业务方法也将加入相应的事务。

UserBean userBean = (UserBean) applicationContext.getBean("userBean");
userBean.hello();
  The UserBean looks like this. Remember from above in the Spring bean configuration we injected the repositoryService into the userBean.

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;
  }
}
 

Expressions

表达式

When using the ProcessEngineFactoryBean, by default, all expressions in the BPMN processes will also 'see' the Spring beans. For example, the SpringTransactionIntegrationTest hello.bpmn20.xml shows how a method on a Spring bean can be invoked using a UEL method expression:

当我们使用ProcessEngineFactoryBean时,缺省的,所有BPMN流程所定义的表达式都可以“看”到Springbean。例如,SpringTransactionIntegrationTest  hello.bpmn20.xml将展示通过UEL方法表达式如何调用Springbean的方法:

<definitions id="definitions" ...>
  
  <process id="helloProcess">
  
    <startEvent id="start" />
    <sequenceFlow id="flow1" sourceRef="start" targetRef="print" />
    
    <serviceTask id="print" 
                 activiti:method-expr="#{printer.printMessage}" />
    <sequenceFlow id="flow2" sourceRef="print" targetRef="end" />
    
    <endEvent id="end" />
    
  </process>

</definitions>
  Where   Printer   looks like this:

Printer定义大致如下:

public class Printer {

  public void printMessage() {
    System.out.println("hello world");
  }
}
  And the Spring bean configuration (also shown above) looks like this:

Spring配置(上面已经描述)如下:

<beans ...>
  ...

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

</beans>
  Automatic resource deployment

资源自动部署

Spring integration also has a special feature for deploying resources. In the configuration of the ProcessEngineFactoryBean, you can specify a set of resources. When the ProcessEngineFactoryBean is initialized, all those resources will be scanned and deployed. There is filtering in place that prevents duplicate deployments. Only when the resources actually have changed, will new deployments be deployed to the Activiti DB.

Spring集成时提供另外一个功能就是部署资源文件。在配置ProcessEngineFactoryBean时你可以指定一系列的资源文件。当ProcessEngineFactoryBean初始化时,这些资源文件将被扫描和部署。部署时可以使用通配符进行配置,并且防止重复部署。只有资源文件被改变时,系统才会自动重新部署到Activiti数据库中。

 

Here's an example

示例如下:

<beans ...>
  ...
  <bean id="processEngine" class="org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean">
    ...
    <property name="deploymentResources" value="classpath*:/org/activiti/examples/spring/autodeploy.*.bpmn20.xml" />
  </bean>

</beans>

 

Unit testing

单元测试

When integrating with Spring, business processes can be tested very easily using the standard Activiti testing facilities. Following example shows how a business process is tested in a typical Spring-based unit test:

当与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());
   
  }
}      
  Note that for this to work, you need to define a  org.activiti.engine.test.ActivitiRule  bean in the Spring configuration (which is injected by auto-wiring in the example above).

注意在这个示例中,你必须在Spring配置文件中定义一个org.activiti.engine.test.ActivitiRule  bean(用于上面示例中的自动注入)。

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

你可能感兴趣的:(spring,bean,xml,jdbc,单元测试)